问题
I'm wondering what the easiest/most elegant way of selecting attributes from join models in has_many :through associations is.
Lets say we have Items, Catalogs, and CatalogItems with the following Item class:
class Item < ActiveRecord::Base
has_many :catalog_items
has_many :catalogs, :through => :catalog_items
end
Additionally, lets say that CatalogueItems has a position attribute and that there is only one CatalogueItem between any catalog and any item.
The most obvious but slightly frustrating way to retrieve the position attribute is:
@item = Item.find(4)
@catalog = @item.catalogs.first
@cat_item = @item.catalog_items.first(:conditions => {:catalog_id => @catalog.id})
position = @cat_item.position
This is annoying because it seems that we should be able to do @item.catalogs.first.position since we have completely specified which position we want: the one that corresponds to the first of @item's catalogs.
The only way I've found to get this is:
class Item < ActiveRecord::Base
has_many :catalog_items
has_many :catalogs, :through => :catalog_items, :select => "catalogue_items.position, catalogs.*"
end
Now I can do Item.catalogs.first.position. However, this seems like a bit of a hack - I'm adding an extra attribute onto a Catalog instance. It also opens up the possibility of trying to use a view in two different situations where I populate @catalogs with a Catalog.find or with a @item.catalogs. In one case, the position will be there, and in the other, it won't.
Does anyone have a good solution to this?
Thanks.
回答1:
You can do something like this:
# which is basically same as your "frustrating way" of doing it
@item.catalog_items.find_by_catalogue_id(@item.catalogs.first.id).position
Or you can wrap it into in an instance method of the Item model:
def position_in_first_catalogue
self.catalog_items.find_by_catalogue_id(self.catalogs.first.id).position
end
and then just call it like this:
@item.position_in_first_catalogue
回答2:
Just adding answer so that it might help others
CatalogItem.joins(:item, :catalog).
where(items: { id: 4 }).pluck(:position).first
回答3:
You should be able to do @catalog.catalog_item.position if you provide the other end of the association.
class Catalog < ActiveRecord::Base
belongs_to :catalog_item
end
Now you can do Catalog.first.catalog_item.position.
回答4:
Why don't You just
@item = Item.find(4)
position = @item.catalog_items.first.position
why do you go through catalogs? It doesn't make any sense to me since you are looking for first ANY catalog!?
来源:https://stackoverflow.com/questions/428066/elegantly-selecting-attributes-from-has-many-through-join-models-in-rails