ruby on rails 3 - has_one - Utilice un ámbito de forma predeterminada en una relación Rails has_many
rails has_many through example (2)
Acabo de sumergirme en ActiveRecord y no parece que esto pueda lograrse con la implementación actual de has_many
. Puedes pasar un bloque a :conditions
pero esto se limita a devolver un hash de condiciones, no cualquier tipo de cosas de tipo arel.
una forma muy simple y transparente de lograr lo que desea (lo que creo que está tratando de hacer) es aplicar el alcance en tiempo de ejecución:
# foo.rb
def bars
super.baz
end
esto está lejos de lo que estás pidiendo, pero podría funcionar;)
Digamos que tengo las siguientes clases
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
tiene un alcance life_supporting
y SolarSystem
life_supporting
SolarSystem
has_many :planets
. Me gustaría definir mi relación has_many para que cuando pregunto a un sistema solar_system
por todos los planets
asociados, el alcance de life_supporting
se aplique automáticamente. Esencialmente, me gustaría solar_system.planets == solar_system.planets.life_supporting
.
Requisitos
No quiero cambiar el
scope :life_supporting
enPlanet
paradefault_scope where(''distance_from_sun > ?'', 5).order(''diameter ASC'')
También me gustaría evitar la duplicación al no tener que agregar a
SolarSystem
has_many :planets, :conditions => [''distance_from_sun > ?'', 5], :order => ''diameter ASC''
Gol
Me gustaría tener algo como
has_many :planets, :with_scope => :life_supporting
Editar: la vuelta al trabajo
Como dijo @phoet, puede que no sea posible alcanzar un alcance predeterminado usando ActiveRecord. Sin embargo, he encontrado dos posibles soluciones alternativas. Ambos evitan la duplicación. El primero, mientras que es largo, mantiene legibilidad y transparencia obvias, y el segundo es un método de tipo colaborador cuya salida es explícita.
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
Otra solución que es mucho más limpia es simplemente agregar el siguiente método a SolarSystem
def life_supporting_planets
planets.life_supporting
end
y para usar solar_system.life_supporting_planets
donde quiera que use solar_system.planets
.
Ninguno de los dos responde la pregunta, así que los puse aquí como una solución alternativa si alguien más se encuentra con esta situación.
En Rails 4, las Associations
tienen un parámetro de scope
opcional que acepta una lambda que se aplica a la Relation
(consulte el documento para ActiveRecord::Associations::ClassMethods )
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
En Rails 3, la solución alternativa where_values
veces se puede mejorar utilizando where_values_hash
que maneja mejores ámbitos donde las condiciones se definen por multiple where
o por un hash (no es el caso aquí).
has_many :planets, conditions: Planet.life_supporting.where_values_hash