¿Cuál es la forma correcta de anular un método setter en Ruby on Rails?
Estoy usando Ruby on Rails 3.2.2 y me gustaría saber si lo siguiente es una forma "adecuada"/"correcta"/"segura" de sobrescribir un método setter para un atributo my class.
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self[:attribute_name] = value
end
El código anterior parece funcionar como se esperaba. Sin embargo, Me gustaría saber si, usando el código anterior, en el futuro tendré problemas o, al menos, qué problemas "debería esperar"/"podría suceder" con Ruby on Rails. Si esa no es la forma correcta de anular un método setter, ¿cuál es la correcta ¿camino?
Nota : Si utilizo el código
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self.attribute_name = value
end
Obtengo el siguiente error:
SystemStackError (stack level too deep):
actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70
5 answers
=========================================================================== Actualización: julio 19, 2017
Ahora la documentación de Rails también sugiere usar super
así:
class Model < ActiveRecord::Base
def attribute_name=(value)
# custom actions
###
super(value)
end
end
===========================================================================
Respuesta original
Si desea anular los métodos setter para las columnas de una tabla mientras accede a través de modelos, esta es la forma haciéndolo.
class Model < ActiveRecord::Base
attr_accessible :attribute_name
def attribute_name=(value)
# custom actions
###
write_attribute(:attribute_name, value)
# this is same as self[:attribute_name] = value
end
end
Ver Sobreescribir los accesos predeterminados en la documentación de Rails.
Por lo tanto, su primer método es la forma correcta de anular los setters de columna en Modelos de Ruby on Rails. Estos accesores ya son proporcionados por Rails para acceder a las columnas de la tabla como atributos del modelo. Esto es lo que llamamos ActiveRecord mapping mapping.
También tenga en cuenta que la attr_accessible
en la parte superior del modelo no tiene nada que ver con los accesorios. Tiene un funcionalidad completamente diferente (ver esta pregunta)
Pero en pure Ruby, si tienes definidos los accesores para una clase y quieres sobrescribir el setter, tienes que hacer uso de la variable de instancia como esta:
class Person
attr_accessor :name
end
class NewPerson < Person
def name=(value)
# do something
@name = value
end
end
Esto será más fácil de entender una vez que sepas lo que hace attr_accessor
. El código attr_accessor :name
es equivalente a estos dos métodos (getter y setter)
def name # getter
@name
end
def name=(value) # setter
@name = value
end
También su segundo método falla porque causará un bucle infinito mientras llama al mismo método attribute_name=
dentro de ese método.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-19 07:28:07
Usa la palabra clave super
:
def attribute_name=(value)
super(value.some_custom_encode)
end
Por el contrario, para anular el lector:
def attribute_name
super.some_custom_decode
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-05 16:09:31
En carriles 4
Digamos que tienes atributo age en tu tabla
def age=(dob)
now = Time.now.utc.to_date
age = now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
super(age) #must add this otherwise you need to add this thing and place the value which you want to save.
end
Nota: Para los recién llegados en rails 4 no es necesario especificar attr_accessible en el modelo. En su lugar, tiene que hacer una lista blanca de sus atributos a nivel de controlador utilizando el método permit.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-10 11:50:30
He encontrado que (al menos para las colecciones de relaciones ActiveRecord) el siguiente patrón funciona:
has_many :specialties
def specialty_ids=(values)
super values.uniq.first(3)
end
(Esto agarra las primeras 3 entradas no duplicadas en el array pasado.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-25 01:26:38
Usando attr_writer
para sobrescribir el setter
attr_writer: attribute_name
def attribute_name=(value)
# manipulate value
# then send result to the default setter
super(result)
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-22 15:23:20