ruby on rails - ¿Qué significa ActiveRecord:: MultiparameterAssignmentErrors?
ruby-on-rails forms (7)
Tengo un formulario de carriles con un campo datetime_select. Cuando intento enviar el formulario, obtengo la siguiente excepción:
ActiveRecord::MultiparameterAssignmentErrors in WidgetsController#update
1 error(s) on assignment of multiparameter attributes
Si se trata de un error de validación, ¿por qué no veo un error en la página?
Esto está en Rails 2.0.2
ActiveRecord arroja la excepción MultiparameterAssignmentErrors cuando intenta establecer una fecha no válida para un atributo de modelos.
Intente elegir una fecha del 31 de noviembre desde el menú desplegable date_select o datetime_select y obtendrá este error.
Este error también puede ocurrir con webrat / pepino al completar los datos del formulario usando una tabla.
por ejemplo, esto no funciona:
When I fill in the following:
| report_from_1i | 2010 |
| report_from_2i | January |
| report_from_3i | 1 |
| report_to_1i | 2010 |
| report_to_2i | February |
| report_to_3i | 1 |
pero esto hace:
When I fill in the following:
| report_from_1i | 2010 |
| report_from_2i | 1 |
| report_from_3i | 1 |
| report_to_1i | 2010 |
| report_to_2i | 2 |
| report_to_3i | 1 |
En mi caso, el complemento ActiveRecord am / pm causó el error a través de un alias_method_chain
incorrecto que alias_method_chain
resultado una excepción StackLevelTooDeep
.
El plugin fue incluido por el complemento discreto_date_picker.
La mirada en esto antes de piratear.
Al igual que Zubin, he visto esta excepción cuando el formulario envía un mes como un nombre de mes en lugar de una cadena de mes numérico (por ejemplo, octubre en lugar de 10).
Un agente de usuario que he encontrado parece enviar el contenido de la etiqueta de opción en lugar del atributo de valor:
Mozilla / 5.0 (SymbianOS / 9.2; U; Series60 / 3.1 NokiaE66-1 / 300.21.012; Perfil / MIDP-2.0 Configuración / CLDC-1.1) AppleWebKit / 413 (KHTML, como Gecko) Safari / 413
Por lo tanto, en el caso de enviar una fecha de múltiples parámetros desde un helper generado select (desde date_select helper) tus parámetros tendrán:
"event"=> {
"start_on(2i)"=>"October",
"start_on(3i)"=>"19",
"start_on(1i)"=>"2010"
}
Esto crea una excepción: ActiveRecord :: MultiparameterAssignmentErrors: 1 error (s) en la asignación de atributos multiparámetro
La mayoría de los agentes de usuario enviarán correctamente:
"event"=> {
"start_on(2i)"=>"10",
"start_on(3i)"=>"19",
"start_on(1i)"=>"2010"
}
Esto no es un error en Rails, es el comportamiento previsto del escritor de atributos de múltiples parámetros. Estoy dispuesto a apostar a que el campo fecha_entrega del póster original en la base de datos es un varchar en lugar de un tipo de fecha o fecha y hora. ActiveRecord usa cada parte del atributo de parámetros múltiples para enviar al nuevo método del tipo serializado. El número 1, 2, 3, etc. indica la posición del parámetro del constructor y la "i" le dice a ActiveRecord que llame a_i en el parámetro antes de pasarlo al constructor. En este caso, todos son "i" porque DateTime.new (año, mes, día) espera tres enteros y no tres cadenas.
Si la columna deliver_date en la base de datos no es un tipo serializado a DateTime, ActiveRecord arrojará una excepción ActiveRecord :: MultiparameterAssignmentErrors porque String.new (2010,2,11) no será exitosa.
Fuente: https://github.com/rails/rails/blob/v3.0.4/activerecord/lib/active_record/base.rb#L1739
Resulta que los rieles utilizan algo llamado asignación de parámetros múltiples para transmitir fechas y horas en partes pequeñas que se reensamblan cuando se asignan params a la instancia del modelo.
Mi problema era que estaba usando un campo de formulario datetime_select para un campo de modelo de fecha. Aparentemente se ahoga cuando la magia multiparamétrica intenta establecer la hora en un objeto Date.
La solución fue usar un campo de formulario date_select
lugar de un datetime_select
.
Super hack, pero necesitaba resolver este problema de inmediato para un proyecto de cliente. Todavía es un error con Rails 2.3.5.
Con date_select
o datetime_select
, si agrega esto a su modelo en el método de initialize
, puede realizar un análisis previo de los atributos serializados en forma pasados para que funcione:
def initialize(attributes={})
date_hack(attributes, "deliver_date")
super(attributes)
end
def date_hack(attributes, property)
keys, values = [], []
attributes.each_key {|k| keys << k if k =~ /#{property}/ }.sort
keys.each { |k| values << attributes[k]; attributes.delete(k); }
attributes[property] = values.join("-")
end
Estoy usando esto con un modelo anidado, polimórfico. Aquí hay una pregunta que tenía mostrando los modelos que estoy usando . Así que necesitaba accepts_nested_attributes_for
con una fecha y hora.
Aquí está la entrada y la salida usando la consola:
e = Event.last
=> #<Event id: 1052158304 ...>
e.model_surveys
=> []
e.model_surveys_attributes = [{"survey_id"=>"864743981", "deliver_date(1i)"=>"2010", "deliver_date(2i)"=>"2", "deliver_date(3i)"=>"11"}]
PRE ATTRIBUTES: {"survey_id"=>"864743981", "deliver_date(1i)"=>"2010", "deliver_date(2i)"=>"2", "deliver_date(3i)"=>"11"}
# run date_hack
POST ATTRIBUTES: {"survey_id"=>"864743981", "deliver_date"=>"2010-2-11"}
e.model_surveys
=> [#<ModelSurvey id: 121, ..., deliver_date: "2010-02-11 05:00:00">]
>> e.model_surveys.last.deliver_date.class
=> ActiveSupport::TimeWithZone
De lo contrario, era nulo o arrojaría el error:
1 error(s) on assignment of multiparameter attributes
Espero que ayude, Lance