我遇到了AR试图建立从其他人继承的模型关联的问题。问题是在调用save方法之前,相关模型正在保存到数据库中。
我在此页http://techspry.com/ruby_and_rails/active-records-or-push-or-concat-method/
中找到了更多信息这真的很奇怪,为什么AR会自动保存附加到关联的模型(使用<<方法)?很明显,即使父元素已经存在,也必须调用save方法。我们可以阻止这个呼叫
@user.reviews.build(good_params)
但是在关联具有层次结构的上下文中这将是一个问题,例如:如果Hunter has_many:animals,而Dog和Cat继承自Animal,我们无法做到
@hunter.dogs.build
@hunter.cats.build
相反,我们坚持
@hunter.animals << Cat.new
@hunter.animals << Dog.new
如果Cat / Dog类没有验证,该对象将自动保存到数据库中。我该如何防止这种行为?
答案 0 :(得分:9)
我发现Rails 3并不完全支持与STI的关联,并且通常需要黑客攻击。阅读此帖http://simple10.com/rails-3-sti/的更多信息。正如其中一条评论中所述,此问题在rails 4 https://github.com/rails/rails/commit/89b5b31cc4f8407f648a2447665ef23f9024e8a5中提及 Rails sux如此糟糕的处理继承=((Hope Rails 4修复了这个问题。
与此同时,我正在使用这个丑陋的解决方法:
animal = @hunter.animals.build type: 'Dog'
然后替换构建的对象,此步骤可能需要反思到锻炼(查看Lucy的回答和评论)
hunter.animals[@hunter.animals.index(animal)] = animal.becomes(Dog)
这将在此上下文中正确运行,因为
hunter.animals[@hunter.animals.index(animal)].is_a? Dog
将返回true,并且不会使用赋值进行数据库调用
答案 1 :(得分:5)
根据Gus的回答,我实施了类似的解决方案:
# instantiate a dog object
dog = Dog.new(name: 'fido')
# get the attributes from the dog, add the class (per Gus's answer)
dog_attributes = dog.attributes.merge(type: 'Dog')
# build a new dog using the correct attributes, including the type
hunter.animals.build(dog_attributes)
请注意,原始的狗对象会被丢弃。根据您需要设置的属性数量,可能更容易做到:
hunter.animals.build(type: 'Dog', name: 'Fido')