Ganti metode atribut ActiveRecord

150

Contoh dari apa yang saya bicarakan:

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

Ini tampaknya berhasil, tetapi saya baru saja membaca bagian tentang mengganti metode atribut dalam ActiveRecord :: Base docs , dan itu menyarankan menggunakanread_attributewrite_attribute metode dan . Saya pikir pasti ada yang salah dengan apa yang saya lakukan dalam contoh di atas; jika tidak, mengapa mereka memberkati metode ini sebagai "cara yang benar" untuk mengganti metode atribut? Mereka juga memaksakan idiom yang lebih buruk, jadi pasti ada alasan bagus ...

Pertanyaan saya yang sebenarnya: Apakah ada yang salah dengan contoh ini?

Ajedi32
sumber

Jawaban:

211

Menggema komentar Gareth ... kode Anda tidak akan berfungsi seperti yang tertulis. Itu harus ditulis ulang dengan cara ini:

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

def name
  read_attribute(:name).downcase  # No test for nil?
end
Aaron Longwell
sumber
Apa yang saya butuhkan. Terima kasih Aaron.
bong
18
Ini tidak lagi benar. Baik super atau ini berfungsi sekarang. Saya belum menguji notasi hash.
heartpunk
2
Di rails 3, metode pembaca yang ditentukan di sini oleh Aaron bekerja, tetapi penulis yang menyebutkan poster asli (memberi makan nama super) berfungsi dengan baik, dan IMHO lebih bersih daripada menulis atribut secara manual seperti yang disarankan Harun.
Batkins
1
Saya telah menguji metode hash yang diberikan oleh mipadi di bawah ini dan ini bekerja seperti mantra (Rails v 3.2.6)
almathie
Bukankah itu jawaban yang tepat? Terima kasih @ Harun, bekerja untuk saya juga.
Sadiksha Gautam
94

Sebagai ekstensi untuk jawaban Aaron Longwell, Anda juga dapat menggunakan "notasi hash" untuk mengakses atribut yang memiliki pengalih dan mutator yang diganti:

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

def name
  self[:name].downcase
end
mipadi
sumber
Notasi Hash mungkin berfungsi, tetapi self.attributepukulan stack pada 3.2.16.
jrhorn424
Ini memiliki keuntungan yang didukungnya ||=untuk gagal bayar:def name; self[:name] ||= 'anon'; end
Paul Cantrell
Bagi saya, notasi hash ini berfungsi. Tapi saya tidak tahu alasannya. Bisakah seseorang menjelaskan?
radiantshaw
-1

Saya memiliki plugin rails yang membuat atribut overriding berfungsi dengan super seperti yang Anda harapkan. Anda dapat menemukannya di github .

Untuk memasang:

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

Menggunakan:

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

Setelah Anda selesai melakukannya, semuanya bekerja:

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