2

私は初心者で、自分のコードを専門家に見せたところhas_many、変数をフィルタリングするために使用すべきではないと言われましたが、scopes.

ユーザー、製品、所有権の 3 つのモデルがあります。

これが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そこで、 andを削除し、 app/models/ownership.rbhas_many :wanted_productsにスコープを作成しました:

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

これで、将来の所有権を見つけることができます: user.ownerships.future. しかし、私が知らないのは、欲しい商品を取得する方法ですか?app/models/product.rbにスコープを作成して、そのようなものを入力できるようにするにはどうすればよいですか:

user.owned_products.wanted
4

1 に答える 1

2

特に製品のサブセットを熱心にロードする必要がある場合は、関連付けの条件に本質的に悪いことはありません。

ただし、必要なスコープを実現するには、Productモデルに追加してプレーン sql に頼る必要があります。これは、フィルターが定義されているモデルとは異なるモデルに適用されるためです。

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

IMHO、最初の解決策の方が良いでしょう。その理由は、何らかの理由でそのスコープを多くのユーザーのブロック内に適用すると、製品を熱心に読み込んでも 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 に答える