Ruby on rails 正在更新关联而不保存它
我有一个模型:Ruby on rails 正在更新关联而不保存它,ruby-on-rails,ruby-on-rails-4,Ruby On Rails,Ruby On Rails 4,我有一个模型: class A < ActiveRecord::Base has_many :B end 由于在appy_更新程序和object.save之间有很多事情要做,所以事务实际上不是一个选项。这就是为什么我真的希望在不立即持久化的情况下更新关联,就像我们对任何其他属性所做的那样 到目前为止,我得到的最接近的解决方案是重写关联缓存(target)。这看起来像: # In the updater A.bs.target.clear params[:bs].each{|b| A.
class A < ActiveRecord::Base
has_many :B
end
由于在appy_更新程序
和object.save
之间有很多事情要做,所以事务实际上不是一个选项。这就是为什么我真的希望在不立即持久化的情况下更新关联,就像我们对任何其他属性所做的那样
到目前为止,我得到的最接近的解决方案是重写关联缓存(target
)。这看起来像:
# In the updater
A.bs.target.clear
params[:bs].each{|b| A.bs.build(b)}
# A.bs now contains the parameters object without doing any update in the database
当需要保存时,我们需要持久化缓存:
new_object = A.bs.target
A.bs(true).replace(new_object)
这项工作,但这种感觉有点黑客,可以很容易打破或有一些不希望的副作用。我正在考虑的另一种方法是添加一个缓存指定对象的方法a#new_bs=
,以及返回缓存对象(如果可用)的方法a#bs
。问得好。
我可以建议使用属性分配而不是集合操作。所有验证将按常规执行-在save
或其他“持久”方法之后执行。您可以编写自己的方法(在模型中或在单独的验证器中)来验证集合
class AController < ApplicationController
def update
@a = A.find(...)
@a.update(a_attributes) # triggers validation, if error occurs - no changes will be persisted and a.errors will be populated
end
def a_attributes
params.require(:a).permit([:attr_of_a, :b_attributes => [:attr_of_b, :_destroy]])
end
end
您可以通过属性删除元素并将其添加到集合中-删除由附加属性\u destroy
执行,该属性可能为“true”或“false”(),添加-通过将父模型设置为接受属性
例如,设置模型A:
class A < ActiveRecord::Base
has_many :b
accepts_nested_attributes_for :b, :allow_destroy => true
validates_associated :b # to validate each element
validate :b_is_correct # to validate whole collection
def b_is_correct
self.bs.each { |b| ... } # validate collection
end
end
在表单上,我们使用了gem嵌套形式(),我推荐它。但是在服务器端,这种方法使用前面提到的属性
\u destroy
。我终于找到了标记\u进行销毁的方法。我的最终解决方案如下所示:
def update
apply_updaters(object, params)
# do some stuff with the updated object
if(validate(object))
object.save(validate: false)
end
a.bs.each(&:mark_for_destruction)
params[:bs].each{|b| a.bs.build(b)}
然后我可以在下面的处理和验证中过滤掉标记为要销毁的条目
感谢@AlkH让我了解了如何接受
的嵌套属性以及如何处理关联的延迟销毁。这样做毫无意义,因为AR只为一些显式方法调用将工作提交给DB。您确定a.bs=[]
中存在此问题吗?您能否在日志中调试并查看确切的SQL执行情况?如果您需要数据库在以前的关联已被销毁而新关联尚未保存时永远不会进入状态:请将更改包装到事务中。这就是你想要的吗?@AlkH来自:“当你将一个对象分配给一个has\u many关联时,该对象会自动保存(以更新其外键)。如果你在一条语句中分配多个对象,那么它们都会被保存。”我想这就是发生在我身上的事情me@D-另一方面,我想做的是有一个端点,它需要一堆B,然后在a上构建它们,这样我可以在a和B上做一些验证。如果验证失败,我不想分配新的Bs,我想恢复到旧的Bs。我不能真正使用事务,因为这一切背后的架构。我希望不调用a.save
就足够了,但从我的测试来看,仅仅调用a.bs=[]
就破坏了当前的bs。我不明白为什么。中止事务时,事务中的所有更改都将恢复。有什么问题吗?谢谢你的回答<代码>接受嵌套的属性,因为
看起来很有趣,我将对此进行研究。其中一个问题是,我们正在使用自定义方法构建B
对象,因此我需要找到一种方法,update(attributes)
最终调用相同的构建方法。
a.bs.each(&:mark_for_destruction)
params[:bs].each{|b| a.bs.build(b)}