Rails:忽略传递给create()的不存在的属性

gjb*_*gjb 27 ruby-on-rails ruby-on-rails-3

我有以下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
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用其他不存在的属性创建新记录,则会产生错误:

Foo.create(a: 'some', b: 'string', c: 'foo', d: 'bar')
ActiveRecord::UnknownAttributeError: unknown attribute: d
Run Code Online (Sandbox Code Playgroud)

有没有办法让create()忽略模型中不存在的属性?或者,在创建新记录之前删除不存在的属性的最佳方法是什么?

非常感谢

jen*_*233 39

试着想出一种可能更有效的方法,但目前:

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
Run Code Online (Sandbox Code Playgroud)


小智 11

我经常使用(简化):

params.select!{|x| Model.attribute_names.index(x)}
Model.update_attributes(params)
Run Code Online (Sandbox Code Playgroud)


iro*_*and 9

您可以使用Hash#slice该方法,该column_names方法也作为类方法存在。

hash = {a: 'some', b: 'string', c: 'foo', d: 'bar'}
Foo.create(hash.slice(*Foo.column_names.map(&:to_sym)))
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么这个答案没有更多票数。它更加简单和可靠。您确定 ``.map(&amp;:to_sym)``` 部分吗?我设法让它与 ``Foo.create(hash.slice(*Foo.column_names))``` 一起工作 (2认同)

Ami*_*bin 7

我刚刚将这个确切的问题升级到Rails 3.2,当我设置:

config.active_record.mass_assignment_sanitizer = :strict
Run Code Online (Sandbox Code Playgroud)

它引起了我的一些创造!调用失败,因为先前被忽略的字段现在导致批量分配错误.我通过伪造模型中的字段来解决这个问题,如下所示:

attr_accessor   :field_to_exclude
attr_accessible :field_to_exclude
Run Code Online (Sandbox Code Playgroud)


Lar*_*y K 6

Re:有没有办法让create()忽略模型中不存在的属性? - 不,这是设计的.

你可以创建一个attr_setter,它将被create-

attr_setter :a # will silently absorb additional parameter 'a' from the form.
Run Code Online (Sandbox Code Playgroud)

Re:或者,在创建新记录之前删除不存在的属性的最佳方法是什么?

您可以明确删除它们:

params[:Foo].delete(:a) # delete the extra param :a
Run Code Online (Sandbox Code Playgroud)

但最好的办法是不要把它们放在首位.修改您的表单以省略它们.

添加:

鉴于更新的信息(传入数据),我想我会创建一个新的哈希:

incoming_data_array.each{|rec|
  Foo.create {:a => rec['a'], :b => rec['b'], :c => rec['c']} # create new
                                                              # rec from specific
                                                              # fields
}
Run Code Online (Sandbox Code Playgroud)

添加更多

# 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
Run Code Online (Sandbox Code Playgroud)

  • @ jenjenut233:有点刺耳.通常情况下,我们会对错误的答案进行投票,建议危险的答案等等.如果答案没有回答OP满意的问题,那么Op不会给它一个复选标记.请记住,答案可能有用或有用(因此值得投票),即使它没有完全解决OP.最后,请记住,一组数据的XML通常会在Ruby/Rails程序中作为记录数组进行解析和使用. (2认同)
  • 我不同意这个答案提供了"远远不能解决"的解决方案.这与我接受的答案之间的唯一区别是,另一个解决方案利用模型中的属性而不需要单独的守护程序阵列.这个答案很有用,所以我已经投票了. (2认同)