¿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.

Author: varatis, 2012-05-29

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.

 56
Author: DVG,
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.

  1. Inicialmente pregunta " ¿existe active_flag dentro del alcance de whats_my_active_flag?
  2. Busca y se da cuenta de que la respuesta es "no", por lo que salta arriba un nivel, a la instancia de someData
  3. Vuelve a preguntar lo mismo: "¿existe active_flag dentro de este alcance?
  4. 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:

  1. Pregunta "¿existe active_flag dentro del alcance de whats_my_active_flag?
  2. 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!

 44
Author: Yuval Karmi,
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.

 1
Author: Dave Newton,
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á.

 0
Author: fangxing,
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