Substituir métodos de atributo ActiveRecord

150

Um exemplo do que estou falando:

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

Isso parece funcionar, mas acabei de ler a seção sobre substituição de métodos de atributo nos documentos ActiveRecord :: Base , e sugere o uso dos métodos read_attributee write_attribute. Eu pensei que deveria haver algo errado com o que estou fazendo no exemplo acima; caso contrário, por que eles abençoariam esses métodos como o "caminho certo" para substituir os métodos de atributo? Eles também estão forçando uma linguagem muito mais feia, então deve haver uma boa razão ...

Minha verdadeira pergunta: há algo de errado com este exemplo?

Ajedi32
fonte

Respostas:

211

Fazendo eco aos comentários de Gareth ... seu código não funcionará como está escrito. Deve ser reescrito desta maneira:

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

def name
  read_attribute(:name).downcase  # No test for nil?
end
Aaron Longwell
fonte
Exatamente o que eu precisava. Obrigado Aaron.
bong
18
Isso não é mais verdade. Super ou isso funciona agora. Eu não testei a notação de hash, no entanto.
heartpunk
2
No Rails 3, o método do leitor especificado aqui por Aaron funciona, mas o escritor que o pôster original especificou (dando o nome a super) funciona bem, e o IMHO é mais limpo do que escrever manualmente o atributo, como sugere Aaron.
Batkins
1
Testei o método de hash determinado por mipadi abaixo e funciona como um encanto (trilhos v 3.2.6)
almathie
Não é a resposta certa? Obrigado @ Aaron, trabalhou para mim também.
Sadiksha Gautam
94

Como uma extensão da resposta de Aaron Longwell, você também pode usar uma "notação de hash" para acessar atributos que substituíram acessadores e mutadores:

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

def name
  self[:name].downcase
end
mipadi
fonte
A notação de hash pode funcionar, mas self.attributeatualiza a pilha no 3.2.16.
Jrhorn424
Isso tem a vantagem que ele suporta ||=por padrão:def name; self[:name] ||= 'anon'; end
Paul Cantrell
Para mim, essa notação hash funciona. Mas não sei o motivo pelo qual isso funciona. Alguém pode explicar?
precisa
-1

Eu tenho um plug-in rails que faz com que a substituição de atributos funcione como super, como seria de esperar. Você pode encontrá-lo no github .

Para instalar:

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

Usar:

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

Depois de fazer isso, as coisas simplesmente funcionam:

$ ./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"
chriseppstein
fonte