是否有相当于assign_attributes
没有属性覆盖的内容?
让我用一个简单的例子解释一下:
my_model = MyModel.new(first_name: 'Romain', age: nil)
new_attributes = {first_name: 'Pierre', last_name: 'Roger', age: 27}
my_model.assign_attributes(new_attributes)
# What I get : <first_name='Pierre', last_name='Roger', age=27>
# * Romain is overwritten by Pierre
# * nil is overwritten by 27
# What I would like : <first_name='Romain', last_name='Roger', age=27>
# * Romain isn't overwritten by Pierre
# * nil is overwritten by 27
我知道我可以做这样的事情,但这似乎不对:
new_attributes.merge(
my_model.slice(:first_name, :last_name, :age)
.select { |_, val| !val.nil? }
)
my_model.assign_attributes(new_attributes)
有什么想法吗?
答案 0 :(得分:2)
正如评论中所提到的,我不认为ActiveRecord中有一个可以使用的方法来执行此操作。但是,您可以编写自己的,甚至更好的 - 修改现有的assign_attributes
方法。当然,我们需要格外小心,不要破坏它的基本功能 - 我们只会稍微扩展它。
assign_attributes
方法在ActiveRecord::AttributeAssignment
模块中定义,然后包含在ActiveRecord::Base
中。我们可以直接在其模块中覆盖它,但是对于新模块来说它似乎更清晰,而是将其包含在ActiveRecord::Base
中(因为我们可以调用super
,而不是别名链接)。将以下代码复制到config/initializers
中的新文件(任何名称都可以):
module ActiveRecord::AttributeAssignmentOverride
def assign_attributes(new_attributes, options={})
return super(new_attributes) if options.fetch(:override, true)
super(new_attributes.select {|k,_| self[k].nil? })
end
end
class ActiveRecord::Base
include ActiveRecord::AttributeAssignmentOverride
end
然后您可以按常规方式使用assign_attributes
(自然重启后):
model.assign_attributes(new_params)
将照常工作,覆盖所有非零值。但是,您现在可以添加额外选项:
model.assign_attributes(new_params, override: false)
不会触及已经指定的值。
上面的代码只能在rails 4中使用.Rails 3使用attr_accessible
代替强参数来进行质量分配安全性。这些可能取决于许多条件,因此在rails 3中,默认assign_attributes
方法接受两个参数(与我们的新参数相同)。这意味着您还需要将选项传递给每次超级调用。
答案 1 :(得分:0)
这对你有用吗?
my_model = MyModel.new(first_name: 'Romain', age: nil)
new_attributes = {first_name: 'Pierre', last_name: 'Roger', age: 27}
my_model.assign_attributes(my_model.attributes.reject{|k,v|v.nil?}.reverse_merge(new_attributes))