2012-05-29 19 views
58

Pregunta: ¿Cuándo debo usar self en mis modelos en Rails?¿Cuándo usar self en Model?

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 de active_flag no cambia, sino que falla silenciosamente. ¿Alguien puede explicar?

No puedo encontrar ningún duplicado, pero si alguien encuentra uno, también está bien.

+0

posible duplicado de [Cuándo usar 'self' en Ruby] (http://stackoverflow.com/questions/1252031/when-to-use-self-in-ruby) – sepp2k

Respuesta

52

Cuando está realizando una acción en la instancia que invoca el método, usa self.

Con este código

class SocialData < ActiveRecord::Base 
    def set_active_flag(val) 
    active_flag = val 
    save! 
    end 
end 

está definiendo una variable local con ámbito completamente nuevo llamado active_flag, estableciéndolo en el pasado en el valor, que no está asociado con cualquier cosa, por lo que es rápidamente tiran cuando el procedimiento termina como nunca existió

self.active_flag = val 

Sin embargo, le dice a la instancia que modifique su propio atributo llamado active_flag, en lugar de una nueva variable. Es por eso que funciona.

+6

"Cuando estás haciendo una acción en la instancia que llama al método, usas uno mismo ". Eso no es del todo exacto. Llamar a un método (no establecedor) en el objeto actual funciona bien sin 'self'. Lo mismo ocurre con el establecimiento de variables de instancia (directamente); de hecho, no se puede hacer eso usando 'self' (sin reflejo de todos modos). – sepp2k

+0

Qué extraño que no haga referencia a la variable de instancia ... otra diferencia de Java. Gracias por la respuesta. – varatis

+3

@varatis: como las variables no se declaran en ruby, la única forma de crear una variable es asignarle algo. Java puede decir si 'foo = bar' se está asignando a una variable local o una variable de instancia, porque simplemente puede ver si se ha declarado una variable local con ese nombre. Ruby no puede hacer eso porque no hay declaraciones. Se podría decir "invoque el método setter si existe, de lo contrario cree una variable local", pero luego tiene problemas con 'method_missing'. También tenga en cuenta que 'self.foo = bar' llama a un método llamado' foo = ', no establece (directamente) una variable de instancia. – sepp2k

1

Para asegurarse de que está utilizando el método setter y no explora 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 existe update_attributes! aunque entiendo el deseo de abstraer.

También hay toggle!, lo que podría ser aún más agradable, dependiendo de su interfaz con la bandera.

+0

podría estar teniendo un problema de modificador pendiente aquí ... ¿está diciendo que el hecho de que "foo = barra" crea una variable local es un detalle de implementación * AR *? – sepp2k

+0

@ sepp2k Eso no tendría ningún sentido, pero mi edición no estaba clara. –

40

Esto sucede debido al alcance. Cuando estás dentro de un método y se intenta establecer una nueva variable de la siguiente manera:

class SomeData < ActiveRecord::Base 
    def set_active_flag(val) 
    active_flag = val 
    end 
end 

Usted está creando una nueva variable marca que vive en el interior de set_active_flag. Tan pronto como se ejecuta, se va, 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 intenta leer una variable de instancia en Ruby, así:

class SomeData < ActiveRecord::Base 
    def whats_my_active_flag 
    puts active_flag 
    end 
end 

que realmente va a obtener self.active_flag (el actual variable de instancia) devuelta.


He aquí por qué:

Rubí hará lo que pueda para evitar volver nil.

  1. Inicialmente pregunta "hace active_flag existen dentro del alcance de whats_my_active_flag?
  2. Se busca y se da cuenta de que la respuesta es 'No', por lo que salta hasta una sola planta, a la instancia de somedata
  3. Pregunta lo mismo otra vez: "¿existe active_flag dentro de este alcance?
  4. La respuesta es "yup" y dice "Tengo algo para ti" y ¡eso lo devuelve!

Sin embargo, si se define active_flag dentro del whats_my_active_flag, y luego se lo solicita, se pasa a través de los pasos de nuevo:

  1. Se pregunta "¿Qué active_flag existen dentro del alcance de whats_my_active_flag
  2. ? La respuesta es "yup", por lo que devuelve ese valor

En cualquier caso, no será cambio el valor de self.active_flag a menos que explícitamente se lo indique.

Una manera fácil de describir este comportamiento es "no quiere decepcionarte" y devuelve nil, 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!

+1

Gran explicación.He estado buscando durante una hora tratando de descubrir por qué necesito usarlo para establecer valores, pero puedo saltar a diferentes métodos y usar lo que aparentemente era una variable local para leer sin usar el auto – bkunzi01

+0

¡Gran explicación! También me confundí la diferencia cuando * lees * o * escribes * la variable – Mario

0

Cuando use active_flag = val ruby ​​pensó que usted está definiendo una variable local, la mejor manera es self.active_flag = val, si lo tiene, espero que sepa que send(:active_flag=, val) también funcionará.

Cuestiones relacionadas