90

次のクラスがあるとしましょう

class SolarSystem < ActiveRecord::Base
  has_many :planets
end

class Planet < ActiveRecord::Base
  scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end

Planetにはスコープlife_supportingとがありSolarSystem has_many :planetsます。has_many 関係を定義して、solar_system関連するすべての を要求するplanetsと、life_supportingスコープが自動的に適用されるようにしたいと思います。本質的に、私は欲しいですsolar_system.planets == solar_system.planets.life_supporting

要件

  • 着替えたくないscope :life_supporting_ Planet_

    default_scope where('distance_from_sun > ?', 5).order('diameter ASC')

  • また、追加する必要がないことで重複を防ぎたいSolarSystem

    has_many :planets, :conditions => ['distance_from_sun > ?', 5], :order => 'diameter ASC'

ゴール

次のようなものが欲しいです

has_many :planets, :with_scope => :life_supporting

編集:回避策

@phoet が言ったように、ActiveRecord を使用してデフォルトのスコープを実現できない場合があります。ただし、2 つの潜在的な回避策を見つけました。どちらも重複を防ぎます。最初のものは長いですが、明らかな可読性と透過性を維持し、2 つ目は出力が明示的なヘルパー型メソッドです。

class SolarSystem < ActiveRecord::Base
  has_many :planets, :conditions => Planet.life_supporting.where_values,
    :order => Planet.life_supporting.order_values
end

class Planet < ActiveRecord::Base
  scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end

よりクリーンな別の解決策は、次のメソッドを単に追加することですSolarSystem

def life_supporting_planets
  planets.life_supporting
end

使用するsolar_system.life_supporting_planets場所ならどこでも使用できますsolar_system.planets

どちらも質問に答えないので、他の誰かがこの状況に遭遇した場合の回避策としてここにそれらを配置します.

4

3 に答える 3

140

Rails 4 では、適用されるラムダを受け入れるAssociationsオプションのパラメーターがあります ( ActiveRecord::Associations::ClassMethodsのドキュメントを参照) 。scopeRelation

class SolarSystem < ActiveRecord::Base
  has_many :planets, -> { life_supporting }
end

class Planet < ActiveRecord::Base
  scope :life_supporting, -> { where('distance_from_sun > ?', 5).order('diameter ASC') }
end

Rails 3 では、条件が複数またはハッシュによって定義されているより適切なスコープwhere_valuesを使用することで、回避策が改善されることがあります(ここではそうではありません)。where_values_hashwhere

has_many :planets, conditions: Planet.life_supporting.where_values_hash
于 2013-10-22T15:05:44.340 に答える
1

私はActiveRecordを深く掘り下げましたが、これが現在の実装で達成できるかどうかはわかりませんhas_many。ブロックをに渡すことはできますが:conditions、これは条件のハッシュを返すことに限定されており、あらゆる種類のアレルのものではありません。

あなたが望むこと(私があなたがやろうとしていると思うこと)を達成するための本当にシンプルで透過的な方法は、実行時にスコープを適用することです:

  # foo.rb
  def bars
    super.baz
  end

これはあなたが求めているものとはほど遠いですが、うまくいくかもしれません;)

于 2012-07-24T19:01:13.943 に答える