Подтвердить что ты не робот

Используйте область действия по умолчанию для отношения 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.

Ни один из ответов не отвечает на вопрос, поэтому я просто помещаю их здесь как работу, если кто-то еще столкнется с этой ситуацией.

4b9b3361

Ответ 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

это далеко не то, о чем вы просите, но это может сработать;)