Comment puis-je écraser une méthode getter dans un modèle ActiveRecord?

98

J'essaie de remplacer une méthode getter pour un modèle ActiveRecord. J'ai un attribut appelé namedans le modèle Categoryet j'aimerais pouvoir faire quelque chose comme ceci:

def name
  name_trans || name
end

Si l' name_transattribut n'est pas nul, alors renvoyez-le, sinon renvoyez l' nameattribut. Comment ferais-je ça?

Cela devrait alors être appelé normalement comme ceci:

@category.name
oyvindhauge
la source

Réponses:

123

Le guide de style des rails recommande d'utiliser self[:attr]over read_attribute(:attr).

Vous pouvez l'utiliser comme ceci:

def name
  name_trans || self[:name]
end
Wonsup Lee
la source
Pourquoi est-ce mieux? Ne vous contentez pas de créer un lien vers d'autres sites, incluez les éléments pertinents ici. Les liens peuvent devenir invalides
JamesT
2
Pour un peu plus de contexte, voir ici: github.com/bbatsov/rails-style-guide/issues/155
mimsugara
98

Mise à jour: La méthode préférée selon le guide de style des rails est d'utiliser à la self[:name]place de read_attributeet write_attribute. Je vous encourage à sauter ma réponse et à préférer celle-ci .


Vous pouvez le faire exactement comme ça, sauf que vous devez utiliser read_attributepour récupérer la valeur de l'attribut name et éviter l'appel récursif à la nameméthode:

def name 
  name_trans || read_attribute(:name)
end
maigre
la source
2
Toute idée pourquoi Rubocop préfère self[:name]plus read_attribute[:name]?
Zack Xu
18

Je voudrais ajouter une autre option pour écraser la méthode getter, qui est simplement : super.

def name
  name_trans || super
end

cela fonctionne non seulement sur la méthode getter des attributs, mais aussi sur les méthodes getter des associations , aussi。

lei liu
la source
1
C'est ce que les guides Rails recommandent actuellement, pour les getters ET les setters: api.rubyonrails.org/classes/ActiveRecord/…
sandre89
5

Remplacer le getter et utiliser read_attributene fonctionne pas pour les associations, mais vous pouvez utiliser à la alias_method_chainplace.

def name_with_override
  name_trans || name_without_override
end

alias_method_chain :name, :override
Patrick Oscity
la source
Pouvez-vous donner un bon exemple ...?
Arup Rakshit
Bien. Je viens de voir le doco . Maintenant, si j'appelle namel'objet modèle, lequel sera appelé - name_with_overrideou name_without_override?
Arup Rakshit
1
nameva maintenant appeler name_with_override. Si vous souhaitez appeler la méthode d'origine pour une raison quelconque, vous pouvez appeler name_without_override.
Patrick Oscity
OI see .. Merci pour vos réponses //
Arup Rakshit
2

Si vous utilisez des attributs de magasin comme celui-ci

store :settings, accessors: [:volume_adjustment] 

ou en utilisant des gemmes comme hstore_accessor un lien de gemme

Vous avez donc fini par utiliser la storeméthode sur le modèle, puis pour remplacer les méthodes que vous ne pouvez pas utiliser self.read_attribute, vous devez utiliser à la place supercomme ça:

def partner_percentage
  super.to_i || 10
end
onemanstartup
la source
0

Si quelqu'un veut mettre à jour la valeur après name_transdans la méthode getter, vous pouvez utiliser self [: name] =.

def name
  self[:name] = name_trans || self[:name]
  # don't do this, it will cause endless loop
  # update(name: name_trans)
end
crocs
la source
0

Vous pouvez utiliser la méthode read_attribute de Rails. Documentation sur les rails

Rajat Bansal
la source
Bien que ce lien puisse répondre à la question, les réponses aux liens uniquement ne sont pas autorisées sur SO, veuillez ajouter du contexte à votre réponse à partir de ce qui se cache derrière ce lien. Merci! :)
AJT82