Kiedy używać self w modelu?

Pytanie: kiedy muszę używać self w moich modelach w Rails?

Mam metodę set w jednym z moich modeli.

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    self.active_flag = val
    self.save!
  end
end
Kiedy to robię, wszystko działa dobrze. Jednak kiedy to robię:
class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

Wartość active_flag nie zmienia się, raczej zawodzi po cichu. Czy ktoś może to wyjaśnić?

Nie mogę znaleźć żadnych duplikatów, ale jeśli ktoś znajdzie, to też jest w porządku.
Author: varatis, 2012-05-29

4 answers

Gdy wykonujesz akcję na instancji wywołującej metodę, używasz self.

Z tym kodem

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

Definiujesz zupełnie nową zmienną lokalną o zasięgu o nazwie active_flag, ustawiając ją na wartość przekazaną, nie jest ona z niczym powiązana, więc jest natychmiast odrzucana, gdy metoda kończy się tak, jakby nigdy nie istniała.

self.active_flag = val

Każe jednak instancji zmodyfikować swój własny atrybut o nazwie active_flag, zamiast zupełnie nowej zmiennej. Dlatego to działa.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-29 19:25:24

Dzieje się tak z powodu zakresu. Gdy jesteś wewnątrz metody i próbujesz ustawić nową zmienną, taką jak ta:

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

Tworzysz nową zmienną, która mieszka wewnątrz set_active_flag. Gdy tylko to się skończy, znika, nie zmieniając w żaden sposób self.active_flag (rzeczywistej zmiennej instancji).

Jednakże (było to dla mnie źródłem nieporozumień): kiedy próbujesz odczytać zmienną instancji w Rubim, jak to:

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

Zostanie zwrócona self.active_flag (zmienna rzeczywistej instancji).


Oto dlaczego:

Ruby zrobi wszystko, aby uniknąć powrotu nil.

  1. początkowo pyta "czy active_flag istnieje w zakresie whats_my_active_flag?
  2. W przeciwieństwie do innych języków, w których nie ma żadnego znaczenia, nie ma znaczenia, czy są to Języki Obce, czy Języki Obce.]}
  3. ponownie pyta o to samo: "czy active_flag istnieje w tym scope?
  4. odpowiedź brzmi "tak" , a więc mówi "mam coś dla Ciebie" i zwraca to!
Jeśli jednak zdefiniujesz active_flag w whats_my_active_flag, a następnie poprosisz o to, przejdzie to ponownie przez kroki:
  1. pyta "czy active_flag istnieje w zakresie whats_my_active_flag?
  2. odpowiedź brzmi "yup" , więc zwraca tę wartość

W obu przypadkach, nie zmieni wartości self.active_flag, chyba że wyraźnie go polecisz.

Łatwy sposób na opisz to zachowanie: "nie chce cię rozczarować" i wróć nil -- więc stara się znaleźć wszystko, co może.

W tym samym czasie "nie chce mieszać danych, których nie zamierzałeś zmienić", więc nie zmienia samej zmiennej instancji.

Mam nadzieję, że to pomoże!

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-23 06:31:57

Ma na celu upewnienie się, że używasz metody setter i nie wyznaczasz nowej zmiennej. Jest to szczegół użycia Ruby i AR, który często podskakuje ludziom (drugim jest (błędne) użycie zmiennej instancji).

Uwaga jest już update_attributes!Chociaż rozumiem pragnienie abstrakcji.

Jest też przełącznik!, który może być jeszcze ładniejszy, w zależności od interfejsu do flagi.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-29 19:24:57

Kiedy używasz active_flag = val ruby myślał, że definiujesz lokalną zmienną, najlepszym sposobem jest self.active_flag = val, jeśli ją masz, mam nadzieję, że wiesz, że send(:active_flag=, val) również zadziała.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-30 15:30:51