¿Cuándo usar uno mismo en el modelo?
Pregunta: ¿cuándo necesito usar self en mis modelos en Rails?
Tengo un método set
en uno de mis modelos.
class SomeData < ActiveRecord::Base
def set_active_flag(val)
self.active_flag = val
self.save!
end
end
Cuando hago esto, todo funciona bien. Sin embargo, cuando hago esto:
class SomeData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
save!
end
end
El valor active_flag no cambia, sino que falla silenciosamente. ¿Alguien puede explicarlo?
No puedo encontrar duplicados, pero si alguien encuentra uno, también está bien.
4 answers
Cuando estás haciendo una acción en la instancia que está llamando al método, usas self.
Con este código
class SocialData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
save!
end
end
Está definiendo una nueva variable local de ámbito llamada active_flag, configurándola en el valor pasado, no está asociada con nada, por lo que se elimina rápidamente cuando el método termina como si nunca hubiera existido.
self.active_flag = val
Sin embargo, le dice a la instancia que modifique su propio atributo llamado active_flag, en lugar de una variable completamente nueva. Es por eso que obrar.
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
2012-05-29 19:25:24
Esto sucede debido al alcance. Cuando estás dentro de un método e intentas establecer una nueva variable como esta:
class SomeData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
end
end
Está creando una nueva variable que vive dentro de set_active_flag. Tan pronto como termine de ejecutarse, desaparece, sin alterar self.active_flag
(la variable de instancia real) de ninguna manera.
SIN EMBARGO (esto fue una fuente de confusión para mí): cuando intentas leer una variable de instancia en ruby, como esto:
class SomeData < ActiveRecord::Base
def whats_my_active_flag
puts active_flag
end
end
Realmente obtendrás self.active_flag
(la variable de instancia real) devuelta.
He aquí por qué:
Ruby hará lo que pueda para evitar regresar nil
.
- Inicialmente pregunta " ¿existe
active_flag
dentro del alcance dewhats_my_active_flag
? - Busca y se da cuenta de que la respuesta es "no", por lo que salta arriba un nivel, a la instancia de someData
- Vuelve a preguntar lo mismo: "¿existe
active_flag
dentro de este alcance? - La respuesta es " sí "y por lo que dice" Tengo algo para ti " y devuelve eso!
Sin embargo, si defines active_flag
dentro de whats_my_active_flag
, y luego lo pides, pasa por los pasos nuevamente:
- Pregunta "¿existe
active_flag
dentro del alcance dewhats_my_active_flag
? - La respuesta es "sí", por lo que devuelve ese valor
En cualquier caso, no cambiará el valor de self.active_flag
a menos que se lo indique explícitamente.
Una manera fácil de describir este comportamiento es" no quiere decepcionarte " y volver nil
so por lo que hace todo lo posible para encontrar lo que pueda.
Al mismo tiempo, "no quiere estropear los datos que no tenía la intención de cambiar" por lo que no altera la variable de instancia en sí.
Espero que esto ayude!
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-12-23 06:31:57
Es para asegurarse de que está utilizando el método setter y no el alcance de una nueva variable. Es un detalle de uso de Ruby y AR que a menudo hace tropezar a las personas (el otro es el (mal)uso de una variable de instancia).
Nota ya hay update_attributes! aunque entiendo el deseo de abstraer.
También hay alternar!, que podría ser aún mejor, dependiendo de su interfaz para la bandera.
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
2012-05-29 19:24:57
Cuando use active_flag = val
ruby pensó que definiría una variable local, la mejor manera es self.active_flag = val
, si la obtuvo, espero que sepa que send(:active_flag=, val)
también funcionará.
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-10-30 15:30:51