3

この問題の背景は非常に複雑で入り組んでおり、簡単な答えを探しているので、問題を説明する際にそれを脇に置き、代わりにこの仮説的な状況を提供します。

Automobile と呼ばれる単純な ActiveRecord モデルがあり、named_scopes が以下のようになっているとします。

named_scope :classic, :conditions => { :build_date <= 1969 }
named_scope :fast, lambda { |speed| :top_speed >= speed }

私が呼び出す場合、スコープ自体を無視します。

Automobile.scopes

これは正確に何を返すのでしょうか?コンソールに表示されるのは次のとおりです。

[ :classic => #<Proc:0x01a543d4@/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87>,
  :fast => #<Proc:0x01a543d4@/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87> ]

これは、キーと値の配列のように思えます。キーは名前付きスコープのシンボルであり、値は ActiveRecord の named_scope.rb ファイルを指す Proc です。

実際の名前付きスコープとして与えられたハッシュまたは Proc が必要な場合 (:classic の場合、「:conditions => { :build_date <= 1969 }」を受け取ることになります)、どうすればこれを見つけることができますか?

いくつかのnamed_scopeを条件付きでマージするプラグインを書いていますが、これに関して抵抗があります。現在、これらのスコープをマージするために以下を使用しています。

scopes_to_use = Automobile.scopes
scoped_options = {}
Automobile.scopes.each do |scope|
    scoped_options.safe_merge!(eval "Automobile.#{scope}(self).proxy_options")
end

ここで行っていることの「正確さ」を無視して、named_scope に与えられた実際の Hash または Proc を取得できるより良い方法はありますか? この関数で「eval」を使用するのは好きではありません。実際に Hash または Proc を取得できれば、より強力なマージ ロジックを導入できるでしょう。これについての考えは大歓迎です。ありがとう。

4

1 に答える 1

2

例で定義した名前付きスコープはどちらも何もしません。それらは構文的に間違っています。それはあなたが抱えているかもしれない問題を引き起こす可能性があります.

例が急いで作成され、実際に機能する例があると仮定します。答えに進みます。

実際の名前付きスコープとして指定されたハッシュまたは Proc を見つけるにはどうすればよいでしょうか。

Model.scopes[:scope_name]プロシージャを提供します。 Model.send(:scope_name).proxy_optionsスコープに指定されたオプションハッシュを提供します。つまり: { :conditions => ["build_date <= ?", 1969] }

モデル内の各名前付きスコープのオプション ハッシュをプログラムで取得するには、次のようにします。

scopes_to_use = Automobile.scopes
scoped_options = {}
Automobile.scopes.keys.each do |scope|
    scoped_options.safe_merge!(Automobile.send(scope).proxy_options)
end

これは、例外が発生する可能性があるため、引数を必要とするスコープではうまく機能しません。残念ながら、私はそれを回避する簡単な方法を考えることができません。

私が思いつく最善の方法は、proc のアリティをテストしてから、一意の仮引数を提供し、返されたプロキシ オプションを分析して、何が変更されたかを把握することです。しかし、名前付きスコープのアリティは -2 であるため、これは大変な作業です。アリティを取得する際にできる最善の方法は、proc を呼び出し、引数エラーをレスキューし、予想される数または引数を解析することです。次に、その数の仮引数を使用します。

プロセス全体が機能するには、レスキュー ブロックといくつかの eval マジックが必要です。これで、安全なマージのために proxy_options ハッシュを処理できます。

要するに、これに近いことをしたいと思うでしょう。それはきれいではありませんが、うまくいきます:

scopes_to_use = Automobile.scopes
    scoped_options = {}
Automobile.scopes.each do |scope,proc|
  next if scope == :scoped
  number_of_args = 1
  begin
    scoped_options.safe_merge! Automobile.send(scope, "#{scope}_argument_1").proxy_options
  rescue 
    $!.to_s.match /(\d+)\)$/
    number_of_args = $1.to_i
    puts number_of_args
  end
     scoped_options.safe_merge!(Automobile.send(scope, *(1..number_of_args).map{|i| "#{scope}_argument_#{i}"}.proxy_options)
end

proxy_options は SQL を実行せず、型チェックも行わないため、これは安全です。

于 2009-10-21T04:52:55.443 に答える