Quelle est la bonne façon de remplacer une méthode de réglage dans Ruby on Rails?

J’utilise Ruby on Rails 3.2.2 et j’aimerais savoir si ce qui suit est un moyen “correct” / “correct” / “sûr” de remplacer une méthode de réglage pour un atsortingbut de classe.

attr_accessible :atsortingbute_name def atsortingbute_name=(value) ... # Some custom operation. self[:atsortingbute_name] = value end 

Le code ci-dessus semble fonctionner comme prévu. Cependant, j’aimerais savoir si, en utilisant le code ci-dessus, j’aurai à l’avenir des problèmes ou, du moins, quels problèmes “devrais-je m’attendre” / “pourrait se produire” avec Ruby on Rails . Si ce n’est pas la bonne façon de remplacer une méthode de réglage, quelle est la bonne façon?


Note : Si j’utilise le code

 attr_accessible :atsortingbute_name def atsortingbute_name=(value) ... # Some custom operation. self.atsortingbute_name = value end 

Je reçois l’erreur suivante:

 SystemStackError (stack level too deep): actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70 

================================================== ========================= Mise à jour: 19 juillet 2017

Maintenant, la documentation Rails suggère également d’utiliser super comme ceci:

 class Model < ActiveRecord::Base def attribute_name=(value) # custom actions ### super(value) end end 

================================================== =========================

Réponse originale

Si vous souhaitez remplacer les méthodes de réglage pour les colonnes d'une table lors de l'access via les modèles, c'est la manière de procéder.

 class Model < ActiveRecord::Base attr_accessible :attribute_name def attribute_name=(value) # custom actions ### write_attribute(:attribute_name, value) # this is same as self[:attribute_name] = value end end 

Voir Remplacement des accesseurs par défaut dans la documentation Rails.

Ainsi, votre première méthode est la façon correcte de remplacer les parameters de colonne dans les modèles de Ruby on Rails. Ces accesseurs sont déjà fournis par Rails pour accéder aux colonnes de la table en tant qu'atsortingbuts du modèle. C'est ce que nous appelons le mappage ORM ActiveRecord.

N'oubliez pas que attr_accessible en haut du modèle n'a rien à voir avec les accesseurs. Il a une fonctionnalité complètement différente (voir cette question )

Mais en pur Ruby, si vous avez défini des accesseurs pour une classe et souhaitez remplacer le setter, vous devez utiliser une variable d'instance comme celle-ci:

 class Person attr_accessor :name end class NewPerson < Person def name=(value) # do something @name = value end end 

Cela sera plus facile à comprendre une fois que vous savez ce attr_accessor fait attr_accessor . Le code attr_accessor :name est équivalent à ces deux méthodes (getter et setter)

 def name # getter @name end def name=(value) # setter @name = value end 

De plus, votre seconde méthode échoue car cela entraînera une boucle infinie car vous appelez la même méthode atsortingbute_name= dans cette méthode.

Utilisez le mot super clé super :

 def atsortingbute_name=(value) super(value.some_custom_encode) end 

Inversement, pour contourner le lecteur:

 def atsortingbute_name super.some_custom_decode end 

En rails 4

laissez dire que vous avez un atsortingbut d’ âge dans votre table

 def age=(dob) now = Time.now.utc.to_date age = now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1) super(age) #must add this otherwise you need to add this thing and place the value which you want to save. end 

Remarque: Pour les nouveaux arrivants dans les rails 4, vous n’avez pas besoin de spécifier attr_accessible dans le modèle. Au lieu de cela, vous devez mettre en liste blanche vos atsortingbuts au niveau du contrôleur en utilisant la méthode d’ autorisation .

J’ai trouvé que (au moins pour les collections de relations ActiveRecord) le modèle suivant fonctionne:

 has_many :specialties def specialty_ids=(values) super values.uniq.first(3) end 

(Ceci récupère les 3 premières entrées non dupliquées du tableau passé.)

Utiliser attr_writer pour écraser setter attr_writer: nom_atsortingbut

  def atsortingbute_name=(value) # manipulate value # then send result to the default setter super(result) end