Используйте область действия по умолчанию для отношения Rails has_many
Скажем, у меня есть следующие классы
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. Однако я нашел две потенциальные проблемы. Оба предотвращают дублирование. Первый, хотя и длительный, сохраняет очевидную читаемость и прозрачность, а второй - метод вспомогательного типа, выход которого явственен.
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
.
Ни один из ответов не отвечает на вопрос, поэтому я просто помещаю их здесь как работу, если кто-то еще столкнется с этой ситуацией.
Ответы
Ответ 1
В Rails 4 Associations
есть необязательный параметр scope
, который принимает lambda, который применяется к Relation
(см. документ для ActiveRecord:: ассоциаций:: методы класса)
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_hash
, который обрабатывает лучшие области применения, где условия определяются несколькими where
или хешем (не здесь).
has_many :planets, conditions: Planet.life_supporting.where_values_hash
Ответ 2
У меня просто было глубокое погружение в ActiveRecord, и это не выглядит, если это может быть достигнуто с текущей реализацией has_many
. вы можете передать блок в :conditions
, но это ограничивается возвратом хэша условий, а не каких-либо вещей isl.
действительно простой и прозрачный способ достижения того, что вы хотите (что, я думаю, вы пытаетесь сделать), - это применить область во время выполнения:
# foo.rb
def bars
super.baz
end
это далеко не то, о чем вы просите, но это может сработать;)