34

has_manyRails 4 では、次のように関係をスコープできます。

class Customer < ActiveRecord::Base
  has_many :orders, -> { where processed: true }
end

そのため、いつでもcustomer.orders処理済みの注文のみを取得できます。

whereしかし、条件を動的にする必要がある場合はどうすればよいでしょうか? スコープラムダに引数を渡すにはどうすればよいですか?

たとえば、マルチテナント環境で顧客が現在ログインしているアカウントの注文のみが表示されるようにします。

これが私が持っているものです:

class Customer < ActiveRecord::Base
  has_many :orders, (account) { where(:account_id => account.id) }
end

しかし、コントローラーまたはビューで正しいアカウントを渡すにはどうすればよいでしょうか? 上記のコードを使用すると、次のようになります。

customers.orders

ID が 1 のアカウントのすべての注文を、一見恣意的に受け取ります。

4

3 に答える 3

39

方法は、追加の拡張セレクターをhas_manyスコープに定義することです。

class Customer < ActiveRecord::Base
   has_many :orders do
      def by_account(account)
         # use `self` here to access to current `Customer` record
         where(:account_id => account.id)
      end
   end
end

customers.orders.by_account(account)

アプローチはAssociation Extension、RailsAssociationページの head で説明されています。

Customerオブジェクトにアクセスできるネストされたメソッドでレコードにアクセスするselfには、現在のCustomerレコードの値が必要です。

Rails (約 5.1) 以降、モデル スコープを同じタイプのモデルhas_manyスコープとマージできます。たとえば、2 つのモデルで次のように同じコードを記述できます。

class Customer < ApplicationRecord
   has_many :orders
end

class Order < ApplicationRecord
   scope :by_account, ->(account) { where(account_id: account.id) }
end

customers.orders.by_account(account)
于 2015-11-26T12:50:30.403 に答える
30

定義したクラスのインスタンスを渡します。あなたの場合、顧客を渡してからアカウントを取得します。

API http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.htmlから

所有者オブジェクトへのアクセス

クエリを作成するときに所有者オブジェクトにアクセスできると便利な場合があります。所有者はパラメーターとしてブロックに渡されます。たとえば、次の関連付けは、ユーザーの誕生日に発生するすべてのイベントを検索します。

class User < ActiveRecord::Base
  has_many :birthday_events, ->(user) { where starts_on: user.birthday }, 
    class_name: 'Event'
end

あなたの例では、次のようになります。

class Customer < ActiveRecord::Base
  has_many :orders, ->(customer) { where(account_id: customer.account.id) }
end
于 2014-12-03T02:09:03.640 に答える
0

これが古いことは知っていますが、まだ回答が受け入れられていないため、その点について私の意見を追加しても誰にも害はないと思いました.

問題は、リレーションシップにスコープを渡すときはいつでもhas_many、所有者クラスのインスタンスを引数として渡すことが可能であるだけでなく、引数を渡す唯一の可能性であることです。つまり、これ以上引数を渡すことはできず、これは常に所有者クラスのインスタンスになります。

だから@RobSobers、あなたが

「一見恣意的に、ID 1 のアカウントのすべての注文を取得します。」

それは恣意的ではありません。リレーションを呼び出したidすべての注文を取得します。customerあなたのコードは次のようなものだったと思います

Customer.first.orders(@some_account_which_is_ignored_anyway)

has_many関係は引数を受け入れることを意図していないようです。

個人的には、@МалъСкрылевъ のソリューションを好みます。

于 2016-11-22T08:16:41.920 に答える