Question: quand dois-je utiliser self dans mes modèles dans Rails?
J'ai une méthode set
dans l'un de mes modèles.
class SomeData < ActiveRecord::Base
def set_active_flag(val)
self.active_flag = val
self.save!
end
end
Quand je fais ça, tout fonctionne bien. Cependant, quand je fais cela:
class SomeData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
save!
end
end
La valeur active_flag ne change pas, mais échoue silencieusement. Quelqu'un peut-il expliquer?
Je ne trouve pas de doublons, mais si quelqu'un en trouve un, ça va aussi.
Lorsque vous effectuez une action sur l'instance qui appelle la méthode, vous utilisez self.
Avec ce code
class SocialData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
save!
end
end
Vous définissez une toute nouvelle variable locale de portée appelée active_flag, la définissant sur la valeur transmise, elle n'est associée à rien, elle est donc rapidement jetée lorsque la méthode se termine comme si elle n'avait jamais existé.
self.active_flag = val
Dit cependant à l'instance de modifier son propre attribut appelé active_flag, au lieu d'une toute nouvelle variable. Voilà pourquoi ça marche.
Cela se produit en raison de la portée. Lorsque vous êtes à l'intérieur d'une méthode et que vous essayez de définir une nouvelle variable comme celle-ci:
class SomeData < ActiveRecord::Base
def set_active_flag(val)
active_flag = val
end
end
Vous créez une toute nouvelle variable qui réside à l'intérieur de set_active_flag. Dès que l'exécution est terminée, elle disparaît, sans altérer self.active_flag
(la variable d'instance réelle) en aucune façon.
CEPENDANT (c'était une source de confusion pour moi): quand vous essayez de lire une variable d'instance dans Ruby, comme ceci:
class SomeData < ActiveRecord::Base
def whats_my_active_flag
puts active_flag
end
end
Vous obtiendrez en fait self.active_flag
(la variable d'instance réelle) retournée.
voici pourquoi:
Ruby fera ce qu'il peut pour éviter de renvoyer nil
.
active_flag
existent dans le cadre de whats_my_active_flag
?active_flag
existe-t-il dans ce domaine?Cependant, si vous définissez active_flag
dans le whats_my_active_flag
, puis demandez-le, il recommence les étapes:
active_flag
existent dans le cadre de whats_my_active_flag
?Dans les deux cas, il ne sera pas changer la valeur de self.active_flag
sauf si vous le lui demandez explicitement.
Un moyen simple de décrire ce comportement est "il ne veut pas vous décevoir" et retourne nil
- donc il fait de son mieux pour trouver ce qu'il peut.
Dans le même temps, "il ne veut pas gâcher des données que vous n'aviez pas l'intention de modifier", il ne modifie donc pas la variable d'instance elle-même.
J'espère que cela t'aides!
C'est pour vous assurer que vous utilisez la méthode setter et que vous ne définissez pas la portée d'une nouvelle variable. C'est un Ruby et détail d'utilisation AR qui fait souvent trébucher les gens (l'autre étant la (mauvaise) utilisation d'une variable d'instance).
Notez qu'il y a déjà pdate_attributes! bien que je comprenne le désir d'abstraire.
Il y a aussi bascule! , ce qui pourrait être encore plus agréable, selon votre interface avec le drapeau.
Lorsque vous utilisez active_flag = val
Ruby pensait que vous définissez une variable locale, la meilleure façon est self.active_flag = val
, Si vous l'avez, j'espère que vous savez que send(:active_flag=, val)
fonctionnera aussi.