แทนที่เมธอดแอ็ตทริบิวต์ ActiveRecord


150

ตัวอย่างของสิ่งที่ฉันพูดถึง:

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

ดูเหมือนว่าจะใช้งานได้ แต่ฉันเพิ่งอ่านหัวข้อเกี่ยวกับวิธีการแทนที่คุณลักษณะในActiveRecord :: Base docsและแนะนำให้ใช้read_attributeและwrite_attributeวิธีการ ฉันคิดว่าต้องมีบางอย่างผิดปกติกับสิ่งที่ฉันทำในตัวอย่างด้านบน มิฉะนั้นเหตุใดพวกเขาจึงอวยพรวิธีเหล่านี้ในฐานะ "วิธีที่ถูกต้อง" เพื่อแทนที่วิธีการของแอตทริบิวต์ พวกเขายังบังคับสำนวนที่ขี้เหร่มากดังนั้นต้องมีเหตุผลที่ดี ...

คำถามจริงของฉัน: มีบางอย่างผิดปกติกับตัวอย่างนี้หรือไม่?

คำตอบ:


211

สะท้อนความคิดเห็นของ Gareth ... รหัสของคุณจะไม่ทำงานตามที่เขียนไว้ ควรเขียนใหม่ด้วยวิธีนี้:

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

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

สิ่งที่ฉันต้องการ ขอบคุณแอรอน

18
สิ่งนี้ไม่เป็นความจริงอีกต่อไป ไม่ว่าจะสุดยอดหรือตอนนี้ใช้งานได้แล้ว อย่างไรก็ตามฉันไม่ได้ทดสอบสัญกรณ์แฮช
heartpunk

2
ใน Rails 3 วิธีอ่านที่ระบุโดย Aaron ทำงาน แต่ผู้เขียนระบุว่าโปสเตอร์ดั้งเดิมที่ระบุ (ให้ชื่อถึง super) นั้นใช้ได้ดีและ IMHO นั้นสะอาดกว่าการเขียนแอตทริบิวต์ด้วยตนเองตามที่แอรอนแนะนำ
Batkins

1
ฉันได้ทดสอบวิธีแฮชที่ mipadi ให้ไว้ด้านล่างแล้วมันใช้งานได้อย่างมีเสน่ห์ (Rails v 3.2.6)
almathie

มันเป็นคำตอบที่ถูกใช่ไหม? ขอบคุณ @Aaron ทำงานให้ฉันด้วย
Sadiksha Gautam

94

ในฐานะที่เป็นส่วนขยายของคำตอบของ Aaron Longwell คุณสามารถใช้ "hash notation" เพื่อเข้าถึงแอ็ตทริบิวต์ที่มี accessors และ mutators ที่ถูกแทนที่:

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

def name
  self[:name].downcase
end

สัญกรณ์แฮอาจทำงานได้ แต่self.attributeพัดสแต็คใน 3.2.16
jrhorn424

นี่เป็นข้อดีที่รองรับ||=การเริ่มต้น:def name; self[:name] ||= 'anon'; end
Paul Cantrell

สำหรับฉันแล้วสัญกรณ์แฮชนี้ใช้งานได้ แต่ฉันไม่ทราบสาเหตุที่ใช้งานได้ มีคนอธิบายได้ไหม
radiantshaw

7

มีบางข้อมูลที่ดีที่มีอยู่ในหัวข้อนี้ที่http://errtheblog.com/posts/18-accessor-missing

ความยาวและสั้นของมันคือ ActiveRecord จัดการกับ super call อย่างถูกต้องสำหรับตัวเข้าถึงแอ็ตทริบิวต์ ActiveRecord


-1

ฉันมีปลั๊กอินรางที่ทำให้การเอาชนะคุณลักษณะทำงานได้ดีอย่างที่คุณคาดหวัง คุณสามารถค้นหาได้ในGitHub GitHub

ติดตั้ง:

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

ใช้:

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

เมื่อคุณทำสิ่งนั้นได้ผล:

$ ./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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.