I have the following Rails model:
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
If I try and create a new record with an additional non-existent attribute, this produces an error:
Foo.create(a: 'some', b: 'string', c: 'foo', d: 'bar')
ActiveRecord::UnknownAttributeError: unknown attribute: d
Is there a way I can get create() to ignore attributes that don't exist in the model? Alternatively, what is the best way to remove non-existent attributes prior to creating the new record?
Many thanks
Trying to think of a potentially more efficient way, but for now:
hash = { :a => 'some', :b => 'string', :c => 'foo', :d => 'bar' }
@something = Something.new
@something.attributes = hash.reject{|k,v| [email protected]?(k.to_s) }
@something.save
I use this frequently (simplified):
params.select!{|x| Model.attribute_names.index(x)}
Model.update_attributes(params)
I just had this exact problem upgrading to Rails 3.2, when I set:
config.active_record.mass_assignment_sanitizer = :strict
It caused some of my create! calls to fail, since fields that were previously ignored are now causing mass assignment errors. I worked around it by faking the fields in the model as follows:
attr_accessor :field_to_exclude
attr_accessible :field_to_exclude
Re: Is there a way I can get create() to ignore attributes that don't exist in the model? -- No, and this is by design.
You can create an attr_setter that will be used by create
--
attr_setter :a # will silently absorb additional parameter 'a' from the form.
Re: Alternatively, what is the best way to remove non-existent attributes prior to creating the new record?
You can remove them explicitly:
params[:Foo].delete(:a) # delete the extra param :a
But the best is to not put them there in the first place. Modify your form to omit them.
Added:
Given the updated info (incoming data), I think I'd create a new hash:
incoming_data_array.each{|rec|
Foo.create {:a => rec['a'], :b => rec['b'], :c => rec['c']} # create new
# rec from specific
# fields
}
Added more
# 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
I came up with a solution that looks like this, you might find it helpful:
def self.create_from_hash(hash)
hash.select! {|k, v| self.column_names.include? k }
self.create(hash)
end
This was an ideal solution for me, because in my case hash
was coming from an ideal data source which mirrored my schema (except there were additional fields).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With