Elegantly selecting attributes from has_many :through join models in Rails

淺唱寂寞╮ 提交于 2019-12-04 09:57:36

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!