Angenommen, ich habe die folgenden Klassen
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
hat einen Umfang life_supporting
und SolarSystem
has_many :planets
. Ich möchte meine has_many-Beziehung so definieren, dass der Bereich automatisch angewendet wird , wenn ich solar_system
nach allen zugeordneten Elementen frage . Im Wesentlichen möchte ich .planets
life_supporting
solar_system.planets == solar_system.planets.life_supporting
Bedarf
Ich nicht ändern wollen
scope :life_supporting
inPlanet
zudefault_scope where('distance_from_sun > ?', 5).order('diameter ASC')
Ich möchte auch Doppelarbeit verhindern, indem ich nichts hinzufügen muss
SolarSystem
has_many :planets, :conditions => ['distance_from_sun > ?', 5], :order => 'diameter ASC'
Tor
Ich hätte gerne so etwas
has_many :planets, :with_scope => :life_supporting
Bearbeiten: Work Around
Wie @phoet sagte, ist es möglicherweise nicht möglich, mit ActiveRecord einen Standardbereich zu erreichen. Ich habe jedoch zwei mögliche Problemumgehungen gefunden. Beides verhindert Doppelarbeit. Die erste Methode ist zwar lang, bietet jedoch eine offensichtliche Lesbarkeit und Transparenz, und die zweite Methode ist eine Hilfsmethode, deren Ausgabe explizit ist.
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
Eine andere Lösung, die viel sauberer ist, besteht darin, einfach die folgende Methode hinzuzufügen SolarSystem
def life_supporting_planets
planets.life_supporting
end
und solar_system.life_supporting_planets
überall dort zu verwenden, wo Sie es verwenden möchten solar_system.planets
.
Keiner von beiden beantwortet die Frage, also habe ich sie hier nur als Workarounds platziert, sollte jemand anderes auf diese Situation stoßen.
where_values
funktioniert möglicherweise nicht mit Hash-Bedingungen:{:cleared => false}
... es gibt eine Reihe von Hashes, die ActiveRecord nicht mag. Als Hack funktioniert das Ergreifen des ersten Elements im Array:Planet.life_supporting.where_values[0]
...where_ast
anstelle vonwhere_values
oderwhere_values_hash
wie verwendet verwenden musste. Arbeitete ein Vergnügen! +1Antworten:
Verfügen Sie in Rails 4
Associations
über einen optionalenscope
Parameter, der ein Lambda akzeptiert, das auf das angewendet wirdRelation
(siehe Dokument für 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
In Rails 3 kann die
where_values
Problemumgehung manchmal verbessert werden, indemwhere_values_hash
bessere Bereiche verwendet werden, in denen Bedingungen durch mehrerewhere
oder durch einen Hash definiert sind (hier nicht der Fall).has_many :planets, conditions: Planet.life_supporting.where_values_hash
quelle
has_many :planets, conditions: Planet.life_supporting.where_values_hash
, um den Geltungsbereich durchzusetzen. Dies ist auch golden für eifriges Laden.where_values_hash
mit Text nicht zu funktionieren, wenn Klauseln, z. B.User.where(name: 'joe').where_values_hash
den Hash der erwarteten Bedingungen zurückgeben, während dies nicht der Fall istUser.where('name = ?', 'Joe').where_values_hash
. Daher wird das Planetenbeispiel wahrscheinlich fehlschlagen.In Rails 5 funktioniert der folgende Code einwandfrei ...
class Order scope :paid, -> { where status: %w[paid refunded] } end class Store has_many :paid_orders, -> { paid }, class_name: 'Order' end
quelle
Ich hatte gerade einen tiefen Einblick in ActiveRecord und es sieht nicht so aus, als ob dies mit der aktuellen Implementierung von erreicht werden kann
has_many
. Sie können einen Block an übergeben:conditions
, dies beschränkt sich jedoch darauf, einen Hash von Bedingungen zurückzugeben, nicht irgendeine Art von Arel-Zeug.Ein wirklich einfacher und transparenter Weg, um das zu erreichen, was Sie wollen (was ich denke, dass Sie versuchen zu tun), besteht darin, den Bereich zur Laufzeit anzuwenden:
# foo.rb def bars super.baz end
das ist weit von dem entfernt, wonach du fragst, aber es könnte einfach funktionieren;)
quelle
has_many
Erklärung vorzunehmen, da dies klarer ist.