2

私は次のような2つのモデルを持っています:

class Country < ActiveRecord::Base
   has_many :cities
end

class City < ActiveRecord::Base
   belongs_to :country
   scope :big, where("population > 1000000")
end

次に、コードで国と都市をロードします。次のようにします。

country = Country.include(:cities).find(id)

しかし、私が実行すると:

country.cities.big

次のクエリでデータベースにヒットします。

SELECT * FROM cities where country_id = 1 AND population > 1000000

これは問題なく動作しますが、:include. アソシエーションが既にロードされている場合、スコープがデータベースにヒットしないように指示する方法はありますか?

アソシエーション拡張機能を使用して実行できますが、通常のスコープでは実行できません。拡張機能では、次のようなことを行います:

has_many :cities do
   def big
      if loaded?
        detect {|city| city.population > 1000000}
      else
        where("population > 1000000")
      end
   end
end

しかし、これは 2 つの場所でスコープを繰り返すことになり、都市モデルでスコープを再利用したいと考えています。

4

1 に答える 1

1

スコープ ロジックは内部で Arel と連携するメソッドを使用しますが、Ruby Enumerables はそれらの使用方法を知りません。Arel または Enumerable メソッドを使用するように変換できる抽象化にロジックをリファクタリングできる場合がありますが、これが常に可能であるとは限りません。

def self.build_scope(abstracted)
  where(abstracted.map(&:to_s).join(' '))
end

def self.build_enum(abstracted)
  select{|city| city.send(abstracted[0]).send(*abstracted[1..2]) }
end

def self.abstract_big
  [:population, ">", 10000]
end

scope :big_scope, build_scope(abstract_big)

def self.big_enum
  build_enum abstract_big      
end

次に、次のことができます。

country.cities.big_enum

より良いアイデアは、必要なスコープに応じて熱心にロードすることです (事前にわかっている場合):

country = Country.include(:cities).merge(City.big).find(id)
于 2012-12-21T15:01:14.787 に答える