我是新手,我只是向专家展示了我的代码,告诉我我不应该使用has_many
过滤我的变量,而是scopes
。
我有三种模式:用户,产品和所有权。
所以这是我在 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
所以我删除了has_many :future_ownerships
和has_many :wanted_products
,并在 app / models / ownership.rb 中创建了一个范围:
class Ownership
scope :future, -> { where owning_date: nil, giving_date: nil }
end
现在我可以找到未来的所有权:user.ownerships.future
。但我不知道的是,如何找回想要的产品?如何在我的 app / models / product.rb 中创建一个范围,以便能够输入类似的内容:
user.owned_products.wanted
答案 0 :(得分: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
更新:刚刚发现了merge
令人惊讶undocumented feature of ActiveRecord。
在其他用途中,它允许您进行连接,并按连接模型上的命名范围进行过滤
换句话说,你可以这样做:
user.owned_products.merge(Ownership.future)
退出强大!