2

I'm a newbie and I just showed my code to an expert, that told me I shouldn't use has_many to filter my variables, but scopes.

I have three models : User, Product and Ownership.

So here is my code in app/models/user.rb :

class User
  has_many :ownerships, foreign_key: "offerer_id",
                         dependent: :destroy
  has_many :owned_products, through: :ownerships,
                             source: :product
  has_many :future_ownerships, -> { where owning_date: nil, giving_date: nil },
                               class_name: "Ownership",
                               foreign_key: "offerer_id"
  has_many :wanted_products, through: :future_ownerships,
                             source: :product
end

So I deleted the has_many :future_ownerships and has_many :wanted_products, and created a scope in app/models/ownership.rb :

class Ownership
  scope :future, -> { where owning_date: nil, giving_date: nil }
end

Now I can find the future ownerships doing this : user.ownerships.future. But what I don't know, is how to retrieve the wanted products ? How can I make a scope in my app/models/product.rb to be able to type something like that :

user.owned_products.wanted
4

1 回答 1

2

关联中的条件本身并没有什么坏处,特别是在您需要急切加载产品子集的情况下。

但是,要实现您需要的范围,您必须将其添加到Product模型上并使用普通 sql,因为过滤器应用于与其定义的模型不同的模型。

class Product
  # not tested 
  scope :wanted, ->{ where("ownerships.owning_dates IS NULL AND ...") }
end

恕我直言,您最好使用第一个解决方案。原因是,如果出于某种原因你在一个有很多用户的块中应用了这个范围,那么尽管急切地加载了产品,你还是会遇到 O(n) 的问题。

User.includes(:owned_products).each do |user|
  user.onwned_products.wanted # => SQL connection
end

更新:刚刚发现ActiveRecordmerge的一个惊人的无证特性

在其他用途​​中,它允许您进行连接,并通过连接模型上的命名范围进行过滤

换句话说,您可以这样做:

user.owned_products.merge(Ownership.future)

放弃强大!

于 2013-07-03T09:30:37.967 回答