59

Rails3プロジェクトがあります。Rails 3には、Arelと、あるスコープを再利用して別のスコープを構築する機能が搭載されています。関係を定義するときにスコープを使用する方法があるかどうか疑問に思っています(たとえば、「has_many」)。

パーミッション列のあるレコードがあります。レコード(リレーションシップを介してアクセスされるレコードも含む)がフィルター処理されるように、アクセス許可列を考慮に入れるdefault_scopeを作成したいと思います。

現在、Rails 3では、default_scope(私が見つけたパッチを含む)は、proc(後期変数バインディングに必要)を渡すための実行可能な手段を提供していません。名前付きスコープを渡すことができるhas_manyを定義することは可能ですか?

名前付きスコープを再利用するというアイデアは、次のようになります。

Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)}
has_many :orders, :scope => Orders.my_orders

または、関係でその名前付きスコープを暗黙的にコーディングすると、次のようになります。

has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}

実行時バインディングを使用してdefault_scopeを適用しようとしています。私はArelアプローチ(ある場合)を使用したいと思いますが、実行可能なオプションを使用します。

現在のユーザーを参照しているため、次のような最後の時点で評価されていない条件に依存することはできません。

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
4

6 に答える 6

21

「名前付きスコープは死んでいる」をご覧になることをお勧めします

著者はそこでアレルがどれほど強力であるかを説明しています:)

お役に立てば幸いです。

編集#12014年3月

いくつかのコメントが述べているように、違いは今や個人的な好みの問題です。

ただし、個人的には、Arelのスコープを上位層(コントローラーまたはモデルに直接アクセスするその他のもの)に公開しないようにすることをお勧めします。そのためには、次のことが必要になります。

  1. スコープを作成し、モデルのメソッドを介して公開します。そのメソッドは、コントローラーに公開するメソッドになります。
  2. モデルをコントローラーに公開したことがない場合(つまり、モデルの上にある種のサービスレイヤーがある場合)、問題はありません。腐敗防止レイヤーサービスであり、スコープの実装方法についてあまり心配することなく、モデルのスコープにアクセスできます。
于 2010-03-30T16:53:10.690 に答える
20

アソシエーション拡張はどうですか?

class Item < ActiveRecord::Base
  has_many :orders do
    def for_user(user_id)
      where(user_id: user_id)
    end
  end
end

Item.first.orders.for_user(current_user)

更新:クラスメソッドやスコープとは対照的なアソシエーション拡張の利点は、アソシエーションプロキシの内部にアクセスできることです。

proxy_association.ownerは、関連付けが含まれているオブジェクトを返します。proxy_association.reflectionは、関連付けを説明するリフレクションオブジェクトを返します。proxy_association.targetは、belongs_toまたはhas_oneの関連オブジェクト、またはhas_manyまたはhas_and_belongs_to_manyの関連オブジェクトのコレクションを返します。

詳細はこちら: http: //guides.rubyonrails.org/association_basics.html#association-extensions

于 2013-03-03T05:01:21.823 に答える
15

スコープの代わりに、クラスメソッドを定義してきました。

def self.age0 do
  where("blah")
end
于 2010-08-18T05:36:06.077 に答える
10

私は次のようなものを使用します:

class Invoice < ActiveRecord::Base
  scope :aged_0,  lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) }
end 
于 2010-07-15T02:42:01.903 に答える
9

異なるモデルのスコープをマージするために、mergeメソッドを使用できます。詳細については、このrailscastでマージを検索してください

于 2012-07-26T13:15:07.190 に答える
3

ユーザーの注文を取得しようとしているだけの場合は、関係を使用してみませんか?

コントローラのcurrent_userメソッドから現在のユーザーにアクセスできると仮定します。

@my_orders = current_user.orders

これにより、ユーザーの特定の注文のみが表示されます。また、任意にネストされた結合を実行して、を使用してより深いリソースを取得することもできます。joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)
于 2011-04-20T03:22:44.970 に答える