109 votes

Remplacer les méthodes d'attributs ActiveRecord

Un exemple de ce dont je parle :

class Person < ActiveRecord::Base
  def name=(name)
    super(name.capitalize)
  end
  def name
    super().downcase  # not sure why you'd do this; this is just an example
  end
end

Cela semble fonctionner, mais je viens de lire la section sur le remplacement des méthodes d'attributs dans la documentation d'ActiveRecord::Base ( http://rails.rubyonrails.com/classes/ActiveRecord/Base.html ), et il suggère d'utiliser les méthodes read_attribute et write_attribute. Je me suis dit qu'il devait y avoir un problème avec ce que je faisais dans l'exemple ci-dessus ; sinon, pourquoi ces méthodes seraient-elles considérées comme la "bonne façon" de remplacer les méthodes d'attributs ? Ils imposent également un idiome beaucoup plus laid, donc il doit y avoir une bonne raison...

Ma vraie question : Y a-t-il quelque chose qui ne va pas dans cet exemple ?

154voto

Aaron Longwell Points 3590

En écho aux commentaires de Gareth... votre code ne fonctionnera pas tel qu'il est écrit. Il devrait être réécrit de cette façon :

def name=(name)
  write_attribute(:name, name.capitalize)
end

def name
  read_attribute(:name).downcase  # No test for nil?
end

66voto

mipadi Points 135410

En complément de la réponse d'Aaron Longwell, vous pouvez également utiliser une "notation de hachage" pour accéder à des attributs dont les accesseurs et les mutateurs ont été remplacés :

def name=(name)
  self[:name] = name.capitalize
end

def name
  self[:name].downcase
end

5voto

jcnnghm Points 3030

Vous trouverez d'excellentes informations sur ce sujet à l'adresse suivante http://errtheblog.com/posts/18-accessor-missing .

En résumé, ActiveRecord traite correctement les appels de super pour les accesseurs d'attributs ActiveRecord.

4voto

Gareth Points 42402

Ma vraie question : Y a-t-il quelque chose qui ne va pas dans cet exemple ?

Oui

Les méthodes d'attributs de votre modèle sont créées de manière dynamique sur la page d'accueil du site. Person ils ne sont pas définis dans la classe ActiveRecord::Base . Pour cette raison, votre super L'appel ne fonctionnera pas et échouera.

-2voto

chriseppstein Points 3559

J'ai un plugin pour rails qui fait en sorte que le remplacement des attributs fonctionne avec super comme on peut s'y attendre. Vous pouvez le trouver sur github .

Pour l'installer :

./script/plugin install git://github.com/chriseppstein/has_overrides.git

A utiliser :

class Post < ActiveRecord::Base

  has_overrides

  module Overrides
    # put your getter and setter overrides in this module.
    def title=(t)
      super(t.titleize)
    end
  end
end

Une fois que vous avez fait ça, les choses fonctionnent :

$ ./script/console 
Loading development environment (Rails 2.3.2)
>> post = Post.new(:title => "a simple title")
=> #<Post id: nil, title: "A Simple Title", body: nil, created_at: nil, updated_at: nil>
>> post.title = "another simple title"
=> "another simple title"
>> post.title
=> "Another Simple Title"
>> post.update_attributes(:title => "updated title")
=> true
>> post.title
=> "Updated Title"
>> post.update_attribute(:title, "singly updated title")
=> true
>> post.title
=> "Singly Updated Title"

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X