优雅地从has_many中选择属性:通过Rails中的连接模型

arj*_*jun 5 ruby ruby-on-rails associations has-many has-many-through

我想知道在has_many中通过连接模型选择属性的最简单/最优雅的方式是:通过关联是什么.

假设我们有Items,Catalogs和CatalogItems,它们包含以下Item类:

class Item < ActiveRecord::Base
      has_many :catalog_items
      has_many :catalogs, :through => :catalog_items
end    
Run Code Online (Sandbox Code Playgroud)

另外,假设CatalogueItems有一个position属性,并且在任何目录和任何项目之间只有一个CatalogueItem.

检索position属性最明显但又有点令人沮丧的方法是:

@item         = Item.find(4)
@catalog      = @item.catalogs.first
@cat_item     = @item.catalog_items.first(:conditions => {:catalog_id => @catalog.id})
position      = @cat_item.position
Run Code Online (Sandbox Code Playgroud)

这很烦人,因为我们似乎应该可以执行@ item.catalogs.first.position,因为我们已经完全指定了我们想要的位置:对应于@ item目录的第一个位置.

我发现得到这个的唯一方法是:

class Item < ActiveRecord::Base
      has_many :catalog_items
      has_many :catalogs, :through => :catalog_items, :select => "catalogue_items.position, catalogs.*"
end
Run Code Online (Sandbox Code Playgroud)

现在我可以做Item.catalogs.first.position.但是,这看起来有点像黑客 - 我在Catalog实例上添加了一个额外的属性.它还开辟了在两种不同情况下尝试使用视图的可能性,在这种情况下,我使用Catalog.find或@ item.catalogs填充@catalogs.在一种情况下,位置将在那里,而在另一种情况下,它不会.

有没有人有这个好的解决方案?

谢谢.

Mil*_*ota 0

你可以这样做:

# which is basically same as your "frustrating way" of doing it
@item.catalog_items.find_by_catalogue_id(@item.catalogs.first.id).position
Run Code Online (Sandbox Code Playgroud)

或者您可以将其包装到 Item 模型的实例方法中:

def position_in_first_catalogue
  self.catalog_items.find_by_catalogue_id(self.catalogs.first.id).position
end
Run Code Online (Sandbox Code Playgroud)

然后像这样调用它:

@item.position_in_first_catalogue
Run Code Online (Sandbox Code Playgroud)