Anular métodos de atributos de ActiveRecord

150

Un ejemplo de lo que estoy hablando:

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

Esto parece funcionar, pero acabo de leer la sección sobre la anulación de los métodos de atributo en los documentos ActiveRecord :: Base , y sugiere usar los métodos read_attributey write_attribute. Pensé que debe haber algo mal con lo que estoy haciendo en el ejemplo anterior; de lo contrario, ¿por qué bendecirían estos métodos como la "forma correcta" de anular los métodos de atributos? También están forzando un idioma mucho más feo, por lo que debe haber una buena razón ...

Mi verdadera pregunta: ¿Hay algo mal con este ejemplo?

Ajedi32
fuente

Respuestas:

211

Haciéndose eco de los comentarios de Gareth ... su código no funcionará como está escrito. Debería reescribirse de esta manera:

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

def name
  read_attribute(:name).downcase  # No test for nil?
end
Aaron Longwell
fuente
Exactamente lo que necesitaba. Gracias Aaron
bong
18
Esto ya no es verdad. O super o esto funciona ahora. Sin embargo, no he probado la notación hash.
heartpunk
2
En los rieles 3, el método del lector especificado aquí por Aaron funciona, pero el escritor que especificó el póster original (alimentando el nombre a super) funciona bien, y en mi humilde opinión es más limpio que escribir manualmente el atributo como sugiere Aaron.
Batkins el
1
He probado el método hash dado por mipadi a continuación y funciona de maravilla (Rails v 3.2.6)
almathie
¿No es la respuesta correcta? Gracias @ Aaron, también trabajó para mí.
Sadiksha Gautam
94

Como una extensión de la respuesta de Aaron Longwell, también puede usar una "notación hash" para acceder a los atributos que han anulado los accesores y mutadores:

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

def name
  self[:name].downcase
end
mipadi
fuente
La notación hash puede funcionar, pero self.attributevuela la pila en 3.2.16.
jrhorn424
Esto tiene la ventaja de que es compatible ||=con el incumplimiento:def name; self[:name] ||= 'anon'; end
Paul Cantrell
Para mí, esta notación hash funciona. Pero no sé la razón por la que funciona. Alguien puede explicar?
radiantshaw
-1

Tengo un complemento de rieles que hace que la anulación de atributos funcione con super como es de esperar. Lo puedes encontrar en github .

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

Una vez que hayas hecho eso, las cosas simplemente funcionan:

$ ./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
fuente