ágil tutorial symfony2 español desarrollo con ruby-on-rails ruby-on-rails-3

ruby on rails - tutorial - Rails: ignorando los atributos no existentes pasados a create()



symfony 3 pdf español (8)

Acabo de tener este problema exacto al actualizar a Rails 3.2, cuando configuré:

config.active_record.mass_assignment_sanitizer = :strict

¡Causó algo de mi creación! las llamadas fallan, ya que los campos que se ignoraron anteriormente ahora están causando errores de asignación en masa. Trabajé a su alrededor falsificando los campos en el modelo de la siguiente manera:

attr_accessor :field_to_exclude attr_accessible :field_to_exclude

Tengo el siguiente modelo de rieles:

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

Si intento crear un nuevo registro con un atributo adicional que no existe, se produce un error:

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

¿Hay alguna forma en que pueda crear () para ignorar atributos que no existen en el modelo? Alternativamente, ¿cuál es la mejor manera de eliminar los atributos que no existen antes de crear el nuevo registro?

Muchas gracias


Creo que usar el método attr_accessible en la clase del modelo para Foo lograría lo que quieres, por ejemplo:

class Foo < ActiveRecord::Base attr_accessible :a, :b, :c ... end

Esto permitiría la configuración / actualización de solo aquellos atributos listados con attr_accessible .


Encontré una solución que funciona bastante bien y, en última instancia, es una combinación de las opciones anteriores. Permite que los parámetros no válidos se pasen (y se ignoren), mientras que los válidos se asignan correctamente al objeto.

def self.initialize(params={}) User.new(params.reject { |k| !User.attribute_method?(k) }) end

Ahora, en lugar de llamar a User.new() , llame a User.initialize() . Esto "filtrará" los parámetros correctos con bastante elegancia.


Intentando pensar en una forma potencialmente más eficiente, pero por ahora:

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


Puede usar Hash#slice método Hash#slice y column_names también existe como método de clase.

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


Re: ¿Hay una manera en que pueda hacer que create () ignore los atributos que no existen en el modelo? - No, y esto es por diseño.

Puede crear un attr_setter que será utilizado por create -

attr_setter :a # will silently absorb additional parameter ''a'' from the form.

Re: Alternativamente, ¿cuál es la mejor manera de eliminar los atributos que no existen antes de crear el nuevo registro?

Puedes eliminarlos explícitamente:

params[:Foo].delete(:a) # delete the extra param :a

Pero lo mejor es no ponerlos allí en primer lugar. Modifica tu formulario para omitirlos.

Adicional:

Dada la información actualizada (datos entrantes), creo que crearía un nuevo hash:

incoming_data_array.each{|rec| Foo.create {:a => rec[''a''], :b => rec[''b''], :c => rec[''c'']} # create new # rec from specific # fields }

Añadido más

# 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


Se me ocurrió una solución que se parece a esto, puede que te resulte útil:

def self.create_from_hash(hash) hash.select! {|k, v| self.column_names.include? k } self.create(hash) end

Esta fue una solución ideal para mí, porque en mi caso el hash provenía de una fuente de datos ideal que reflejaba mi esquema (excepto que había campos adicionales).


Yo uso esto con frecuencia (simplificado):

params.select!{|x| Model.attribute_names.index(x)} Model.update_attributes(params)