我有以下Rails模型:
class CreateFoo < ActiveRecord::Migration
def self.up
create_table :foo do |t|
t.string :a
t.string :b
t.string :c
t.timestamps
end
end
def self.down
drop_table :foo
end
end
如果我尝试使用其他不存在的属性创建新记录,则会产生错误:
Foo.create(a: 'some', b: 'string', c: 'foo', d: 'bar')
ActiveRecord::UnknownAttributeError: unknown attribute: d
有没有办法让create()忽略模型中不存在的属性?或者,在创建新记录之前删除不存在的属性的最佳方法是什么?
非常感谢
答案 0 :(得分:36)
尝试考虑一种可能更有效的方法,但目前:
hash = { :a => 'some', :b => 'string', :c => 'foo', :d => 'bar' }
@something = Something.new
@something.attributes = hash.reject{|k,v| !@something.attributes.keys.member?(k.to_s) }
@something.save
答案 1 :(得分:10)
我经常使用(简化):
params.select!{|x| Model.attribute_names.index(x)}
Model.update_attributes(params)
答案 2 :(得分:7)
当我设置时,我刚刚将此问题升级到Rails 3.2:
config.active_record.mass_assignment_sanitizer = :strict
它引起了我的一些创造!调用失败,因为先前被忽略的字段现在导致批量分配错误。我通过伪造模型中的字段来解决这个问题:
attr_accessor :field_to_exclude
attr_accessible :field_to_exclude
答案 3 :(得分:6)
Re:有没有办法让create()忽略模型中不存在的属性? - 不,这是设计的。
您可以创建将由create
-
attr_setter :a # will silently absorb additional parameter 'a' from the form.
Re:或者,在创建新记录之前删除不存在的属性的最佳方法是什么?
您可以明确删除它们:
params[:Foo].delete(:a) # delete the extra param :a
但最好不要把它们放在首位。修改您的表单以省略它们。
<强>加了:强>
鉴于更新的信息(传入数据),我想我会创建一个新的哈希:
incoming_data_array.each{|rec|
Foo.create {:a => rec['a'], :b => rec['b'], :c => rec['c']} # create new
# rec from specific
# fields
}
添加更多
# Another way:
keepers = ['a', 'b', 'c'] # fields used by the Foo class.
incoming_data_array.each{|rec|
Foo.create rec.delete_if{|key, value| !keepers.include?(key)} # create new rec
} # from kept
# fields
答案 4 :(得分:3)
我提出了一个看起来像这样的解决方案,你可能会发现它很有用:
def self.create_from_hash(hash)
hash.select! {|k, v| self.column_names.include? k }
self.create(hash)
end
这对我来说是一个理想的解决方案,因为在我的情况下hash
来自一个理想的数据源,它反映了我的模式(除了有其他字段)。
答案 5 :(得分:1)
我认为在Foo的模型类中使用 attr_accessible 方法可以达到你想要的效果,例如:
class Foo < ActiveRecord::Base
attr_accessible :a, :b, :c
...
end
这样只允许设置/更新 attr_accessible 列出的属性。
答案 6 :(得分:0)
我找到了一个运行良好的解决方案,并且最终是上述选项的组合。它允许传递(并忽略)无效参数,而有效参数则正确映射到对象。
def self.initialize(params={})
User.new(params.reject { |k| !User.attribute_method?(k) })
end
现在,不要致电User.new()
,而是致电User.initialize()
。这将相当优雅地“过滤”正确的参数。
答案 7 :(得分:0)
您可以使用Hash#slice
和column_names
方法作为类方法。
hash = {a: 'some', b: 'string', c: 'foo', d: 'bar'}
Foo.create(hash.slice(*Foo.column_names.map(&:to_sym)))