Zastąp metody atrybutów ActiveRecord

150

Przykład o czym mówię:

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

Wydaje się, że to działa, ale właśnie przeczytałem sekcję dotyczącą zastępowania metod atrybutów w dokumentacji ActiveRecord :: Base i sugeruje użycie metod read_attributei write_attribute. Pomyślałem, że coś musi być nie tak z tym, co robię w powyższym przykładzie; w przeciwnym razie dlaczego mieliby błogosławić te metody jako „właściwą drogę” do zastępowania metod atrybutów? Wymuszają też znacznie brzydszy idiom, więc musi być dobry powód ...

Moje prawdziwe pytanie: czy coś jest nie tak z tym przykładem?

Ajedi32
źródło

Odpowiedzi:

211

Powtarzając komentarze Garetha ... Twój kod nie będzie działał tak, jak został napisany. Powinien zostać przepisany w ten sposób:

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

def name
  read_attribute(:name).downcase  # No test for nil?
end
Aaron Longwell
źródło
Dokładnie to, czego potrzebowałem. Dzięki Aaron.
bong
18
To już nie jest prawdą. Albo super, albo to działa teraz. Nie testowałem jednak notacji hash.
heartpunk
2
W railsach 3 działa metoda czytnika określona tutaj przez Aarona, ale autor, który podał oryginalny plakat (przekazujący nazwę do super) działa dobrze, a IMHO jest czystszy niż ręczne zapisywanie atrybutu, jak sugeruje Aaron.
Batkins
1
Przetestowałem metodę haszowania podaną przez mipadi poniżej i działa jak urok (Rails v 3.2.6)
almathie
Czy to nie jest właściwa odpowiedź? Dzięki @Aaron, również dla mnie pracował.
Sadiksha Gautam,
94

Jako rozszerzenie odpowiedzi Aarona Longwella możesz także użyć „notacji mieszającej”, aby uzyskać dostęp do atrybutów, które przesłaniały akcesory i mutatory:

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

def name
  self[:name].downcase
end
mipadi
źródło
Notacja z krzyżykiem może działać, ale self.attributezdmuchuje stos w wersji 3.2.16.
jrhorn424
Ma to tę zaletę, że obsługuje ||=domyślne:def name; self[:name] ||= 'anon'; end
Paul Cantrell
U mnie działa ta notacja hash. Ale nie wiem, dlaczego to działa. Czy ktoś może wyjaśnić?
radiantshaw
-1

Mam wtyczkę rails, która sprawia, że ​​nadpisywanie atrybutów działa z super, jak można się spodziewać. Możesz go znaleźć na githubie .

Żeby zainstalować:

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

Używać:

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

Kiedy już to zrobisz, wszystko po prostu działa:

$ ./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
źródło