# Models
class Animal < ActiveRecord::Base
belongs_to :zoo
end
class Dog < Animal
belongs_to :leg
end
class Snake < Animal
end
class Leg < ActiveRecord::Base
end
class Zoo
has_many :animals
end
# Test, which fails with
# Association named 'leg' was not found on Animal; perhaps you misspelled it?
Zoo.first.animals.
.where(:type => 'Dog')
.includes(:leg)
在这个例子中,Rails无法知道所查询对象的特定类型(它必须分析where
语句,它似乎没有这样做。因此,它失败了,因为关联没有在通用模型Animal
上定义,而是在Dog
模型上定义。
有没有办法指定要检索的对象的类型,以便该示例有效?
答案 0 :(得分:1)
我想出了一个(至少是临时的)解决方案。这个猴子补丁扩展了Rails,其功能是在访问集合关联时指定类覆盖。
用法:
Zoo.first.animals(false, Dog)
.includes(Leg)
猴子补丁(铁轨3!):
# This monkey patch extends the rails collection association reader (i.e. )
# zoo.animals by a second option called `class_override`. Using this option,
# a custom model class for the objects to be retrieved can be specified.
#
# Might only work with rails 3.
#
# @see http://stackoverflow.com/q/25887230
module ActiveRecord
module Associations
class CollectionAssociation < Association #:nodoc:
# Implements the reader method, e.g. foo.items for Foo.has_many :items
def reader(force_reload = false, class_override = nil)
if force_reload
klass.uncached { reload }
elsif stale_target?
reload
end
if class_override.nil?
association = self
else
reflection = self.reflection.dup
reflection.instance_variable_set(:@klass, class_override)
association = self.dup
association.instance_variable_set(:@reflection, reflection)
end
CollectionProxy.new(association)
end
end
end
end
可能也可以使用关联扩展来实现。我正在研究它。
答案 1 :(得分:1)
刚刚在Robert Pankowecki的一篇精彩博客文章中找到了解释可能的解决方案:http://blog.arkency.com/2013/07/sti/。
答案 2 :(得分:0)
class Zoo < ActiveRecord::Base
has_many :animals
has_many :dogs
end
然后尝试:Zoo.first.dogs.includes(:leg)
如果您需要Animal
腿,可以尝试:
class Animal < ActiveRecord::Base
belongs_to :zoo
scope :with_legs, -> { where("leg_id IS NOT NULL").includes(:leg) }
end
然后:Zoo.first.animals.with_legs