J'utilise Ruby sur Rails 3.2.2 et je voudrais savoir si ce qui suit est un moyen "correct"/"correct"/"sûr" pour remplacer une méthode de définition pour un attribut de ma classe.
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self[:attribute_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-il se produire" avec Ruby sur Rails Si ce n'est pas la bonne façon de remplacer une méthode de définition, quelle est la bonne?
Note: Si j'utilise le code
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self.attribute_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, le 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 définition pour les colonnes d'une table lors de l'accès via des modèles, procédez comme suit.
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 bonne façon de remplacer les colonnes dans les modèles de Ruby sur Rails. Ces accesseurs sont déjà fournis par Rails pour accéder aux colonnes de la table en tant qu’attributs du modèle, c’est ce que nous appelons le mappage ActiveRecord ORM.
Rappelez-vous également que le attr_accessible
au sommet 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 séparateur, 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
Ce sera plus facile à comprendre une fois que vous saurez ce que attr_accessor
Est-ce que. 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 deuxième méthode échoue car elle provoquera une boucle infinie puisque vous appelez la même méthode attribute_name=
à l'intérieur de cette méthode.
Utilisez le mot-clé super
:
def attribute_name=(value)
super(value.some_custom_encode)
end
Inversement, pour remplacer le lecteur:
def attribute_name
super.some_custom_decode
end
In Rails 4
disons que vous avez l'attribut age 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 venus dans Rails 4, vous n'avez pas besoin de spécifier attr_accessible dans le modèle. Vous devez plutôt répertorier vos attributs au niveau du contrôleur à l'aide de - permis méthode.
J'ai constaté 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 saisit les 3 premières entrées non dupliquées du tableau passé.)
En utilisant attr_writer
pour écraser le setter attr_writer: nom_attribut
def attribute_name=(value)
# manipulate value
# then send result to the default setter
super(result)
end