ความแตกต่างระหว่าง attr_accessor และ attr_accessible


235

ใน Rails อะไรคือความแตกต่างระหว่างattr_accessorและattr_accessible? จากความเข้าใจของฉันโดยใช้attr_accessorใช้ในการสร้างทะเยอทะยานและวิธีการในการตั้งค่าตัวแปรที่เพื่อให้เราสามารถเข้าถึงตัวแปรเหมือนหรือObject.variableObject.variable = some_value

ฉันอ่านว่าattr_accessibleทำให้ตัวแปรเฉพาะนั้นเข้าถึงได้จากโลกภายนอก ใครช่วยได้โปรดบอกฉันว่าอะไรคือความแตกต่าง


4
คุณถูกต้องที่attr_accessorใช้ในการสร้างวิธีการทะเยอทะยานและ Setter โปรดดูคำตอบของฉันสำหรับคำถามก่อนหน้านี้สำหรับคำอธิบายที่ครอบคลุมมากของattr_accessible: stackoverflow.com/questions/2652907/ …จากนั้นอัปเดตคำถามของคุณหากคุณต้องการรายละเอียดเฉพาะอื่น ๆ หลังจากนั้น
mikej

2
attr_accessible ไม่ได้รับการสนับสนุนในทางรถไฟ 4 เว้นแต่คุณจะใช้ protected_attributes อัญมณีตามคำตอบด้านบนเพื่อstackoverflow.com/questions/17371334/... (กรกฎาคม 2014)
ทราย

คำตอบ:


258

attr_accessorเป็นวิธีทับทิมที่ทำให้ทะเยอทะยานและ Setter attr_accessibleเป็นวิธีการทางรถไฟที่ช่วยให้คุณผ่านในการกำหนดค่ามวล: หรือnew(attrs)update_attributes(attrs)

นี่คือการมอบหมายจำนวนมาก:

Order.new({ :type => 'Corn', :quantity => 6 })

คุณสามารถจินตนาการได้ว่าคำสั่งซื้ออาจมีรหัสส่วนลดด้วยเช่น:price_offกัน หากคุณไม่ติดแท็ก:price_offในขณะที่attr_accessibleคุณหยุดโค้ดที่เป็นอันตรายไม่ให้ทำเช่นนั้น:

Order.new({ :type => 'Corn', :quantity => 6, :price_off => 30 })

แม้ว่าแบบฟอร์มของคุณจะไม่มีฟิลด์สำหรับ:price_offแต่ถ้าอยู่ในแบบจำลองของคุณก็จะพร้อมใช้งานตามค่าเริ่มต้น นี่หมายความว่า POST ที่สร้างขึ้นแล้วยังคงสามารถตั้งค่าได้ การใช้attr_accessibleสีขาวแสดงรายการสิ่งต่าง ๆ ที่สามารถมอบหมายได้


2
ทำไมไม่attr_accessibleอยู่ในเอกสารประกอบ Rails? api.rubyonrails.org
Chloe

19
ดูเหมือน Rails4 มีวิธีการใหม่ในการทำสิ่งต่างๆ ดูคำตอบนี้: stackoverflow.com/questions/17371334/…
พอลรูเบล

1
เนื่องจากพารามิเตอร์ที่แข็งแกร่งได้แทนที่การใช้attr_accessible edgeguides.rubyonrails.org/ …
Imran Ahmad

173

หลายคนในชุดข้อความนี้และบน google อธิบายได้ดีมากซึ่งattr_accessibleระบุรายการที่อนุญาตของแอตทริบิวต์ที่ได้รับอนุญาตให้อัปเดตเป็นกลุ่ม ( คุณลักษณะทั้งหมดของรูปแบบวัตถุพร้อมกันในเวลาเดียวกัน ) เป็นส่วนใหญ่ (และเท่านั้น) เพื่อปกป้องแอปพลิเคชันของคุณ จากการใช้ประโยชน์จากโจรสลัด "การมอบหมายจำนวนมาก"

นี่คือคำอธิบายที่นี่ในเอกสารทางรถไฟอย่างเป็นทางการ: การมอบหมายจำนวนมาก

attr_accessorเป็นรหัสทับทิมเพื่อ (อย่างรวดเร็ว) สร้างเมธอดและทะเยอทะยานในคลาส นั่นคือทั้งหมดที่

ตอนนี้สิ่งที่ขาดหายไปตามคำอธิบายก็คือเมื่อคุณสร้างลิงก์ระหว่างโมเดล (Rails) กับตารางฐานข้อมูลคุณไม่จำเป็นไม่จำเป็นต้องใช้attr_accessorโมเดลของคุณในการสร้าง setters และ getters เพื่อที่จะสามารถปรับเปลี่ยน บันทึกของตาราง

นี่เป็นเพราะโมเดลของคุณสืบทอดวิธีการทั้งหมดจากActiveRecord::BaseClass ซึ่งกำหนด accessors CRUD พื้นฐาน (สร้าง, อ่าน, อัปเดต, ลบ) ให้คุณแล้ว นี่คือคำอธิบายในเอกสารอย่างเป็นทางการที่นี่Rails Modelและที่นี่การเขียนทับค่าเริ่มต้น accessor (เลื่อนลงไปที่บท "Overwrite default accessor")

พูดเช่น: เรามีตารางฐานข้อมูลชื่อ "ผู้ใช้" ที่มีสามคอลัมน์ "ชื่อ", "นามสกุล" และ "บทบาท":

คำแนะนำ SQL:

CREATE TABLE users (
  firstname string,
  lastname string
  role string
);

ฉันสันนิษฐานว่าคุณตั้งค่าตัวเลือกconfig.active_record.whitelist_attributes = trueใน config / environment / production.rb เพื่อป้องกันแอปพลิเคชันของคุณจากการใช้ประโยชน์จากการมอบหมายจำนวนมาก นี่คือคำอธิบายที่นี่: การมอบหมายจำนวนมาก

โมเดล Rails ของคุณจะทำงานกับ Model ได้อย่างสมบูรณ์ด้านล่าง:

class User < ActiveRecord::Base

end

อย่างไรก็ตามคุณจะต้องอัปเดตแต่ละแอตทริบิวต์ของผู้ใช้แยกต่างหากในคอนโทรลเลอร์ของคุณเพื่อให้มุมมองฟอร์มของคุณทำงาน:

def update
    @user = User.find_by_id(params[:id])
    @user.firstname = params[:user][:firstname]
    @user.lastname = params[:user][:lastname]

    if @user.save
        # Use of I18 internationalization t method for the flash message
        flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
    end

    respond_with(@user)
end

ตอนนี้เพื่อความสะดวกในชีวิตของคุณคุณไม่ต้องการให้ตัวควบคุมที่ซับซ้อนสำหรับรูปแบบผู้ใช้ของคุณ ดังนั้นคุณจะใช้attr_accessibleวิธีพิเศษในรุ่น Class ของคุณ:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

ดังนั้นคุณสามารถใช้ "ทางหลวง" (การกำหนดจำนวนมาก) เพื่ออัปเดต:

def update
    @user = User.find_by_id(params[:id])

    if @user.update_attributes(params[:user])
        # Use of I18 internationlization t method for the flash message
        flash[:success] = t('activerecord.successful.messages.updated', :model => User.model_name.human)
    end

    respond_with(@user)
end

คุณไม่ได้เพิ่มแอททริบิวต์ "บทบาท" ลงในattr_accessibleรายการเนื่องจากคุณจะไม่ให้ผู้ใช้กำหนดบทบาทของตนเอง (เช่นผู้ดูแลระบบ) คุณทำสิ่งนี้ด้วยตัวคุณเองบนมุมมองผู้ดูแลระบบพิเศษอื่น

แม้ว่ามุมมองผู้ใช้ของคุณจะไม่แสดงฟิลด์ "บทบาท" แต่โจรสลัดอาจส่งคำขอ HTTP POST ที่รวมถึง "บทบาท" ในแฮช params ได้อย่างง่ายดาย แอตทริบิวต์ "role" ที่หายไปattr_accessibleคือการปกป้องแอปพลิเคชันของคุณ

คุณยังคงสามารถแก้ไขแอตทริบิวต์ user.role ของคุณเองได้เหมือนด้านล่าง แต่ไม่สามารถใช้ร่วมกับแอตทริบิวต์ทั้งหมดได้

@user.role = DEFAULT_ROLE

ทำไมนรกคุณจะใช้attr_accessor?

ในกรณีนี้ผู้ใช้ของคุณจะแสดงเขตข้อมูลที่ไม่มีอยู่ในตารางผู้ใช้ของคุณเป็นคอลัมน์

ตัวอย่างเช่นสมมติว่ามุมมองผู้ใช้ของคุณแสดงฟิลด์ "Please-tell-the-admin-that-I'm-in-here" คุณไม่ต้องการจัดเก็บข้อมูลนี้ในตารางของคุณ คุณเพียงแค่ต้องการให้ Rails ส่งอีเมลเตือนคุณว่ามีผู้ใช้ "คนบ้า" ;-) สมัครรับข้อมูล

เพื่อให้สามารถใช้ประโยชน์จากข้อมูลนี้ได้คุณจะต้องเก็บมันไว้ชั่วคราว อะไรจะง่ายไปกว่าการกู้คืนในuser.peekabooแอตทริบิวต์

ดังนั้นคุณเพิ่มฟิลด์นี้ในโมเดลของคุณ:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

ดังนั้นคุณจะสามารถใช้user.peekabooคุณสมบัติที่มีการศึกษาเพื่อควบคุมการส่งอีเมลหรือทำสิ่งที่คุณต้องการ

ActiveRecord จะไม่บันทึกแอตทริบิวต์ "peekaboo" ในตารางของคุณเมื่อคุณทำuser.saveเพราะเธอไม่เห็นคอลัมน์ใด ๆ ที่ตรงกับชื่อนี้ในรูปแบบของเธอ


48

attr_accessorเป็นวิธี Ruby ที่ให้ setter และ getter method กับตัวแปร instance ในชื่อเดียวกัน ดังนั้นจึงเท่ากับ

class MyModel
  def my_variable
    @my_variable
  end
  def my_variable=(value)
    @my_variable = value
  end
end

attr_accessible เป็นวิธี Rails ที่กำหนดตัวแปรที่สามารถตั้งค่าในการมอบหมายจำนวนมาก

เมื่อคุณส่งแบบฟอร์มและคุณมีสิ่งที่ต้องการMyModel.new params[:my_model]แล้วคุณต้องการควบคุมเพิ่มเติมอีกเล็กน้อยเพื่อให้คนไม่สามารถส่งสิ่งที่คุณไม่ต้องการ

คุณอาจทำattr_accessible :emailเช่นนั้นเมื่อมีคนอัปเดตบัญชีของพวกเขาพวกเขาสามารถเปลี่ยนที่อยู่อีเมลของพวกเขาได้ แต่คุณจะไม่ทำattr_accessible :email, :salaryเพราะคน ๆ นั้นสามารถกำหนดเงินเดือนของพวกเขาผ่านการส่งแบบฟอร์ม กล่าวอีกนัยหนึ่งพวกเขาสามารถแฮ็กเพื่อยกระดับ

ข้อมูลประเภทนั้นจะต้องได้รับการจัดการอย่างชัดเจน เพียงลบออกจากแบบฟอร์มไม่เพียงพอ บางคนสามารถใช้ firebug และเพิ่มองค์ประกอบลงในแบบฟอร์มเพื่อส่งฟิลด์เงินเดือน พวกเขาสามารถใช้ built-in curl เพื่อส่งเงินเดือนใหม่ไปยังวิธีการอัพเดทคอนโทรลเลอร์ได้พวกเขาสามารถสร้างสคริปต์ที่ส่งโพสต์ด้วยข้อมูลนั้น

ดังนั้นattr_accessorเกี่ยวกับการสร้างวิธีการเก็บตัวแปรและattr_accessibleเกี่ยวกับความปลอดภัยของการมอบหมายจำนวนมาก


2
คุณพิมพ์ผิดหลังจากบล็อกโค้ดมันควรจะบอกว่าattr_accesible
Chubas

ยิ่งใหญ่เขียนขึ้นฉันชอบตัวอย่างชั้นเรียน คะแนนโบนัสพิเศษ (ปลอม) สำหรับการรวมคำอธิบาย:as!
Ian Vaughan

รุ่นถูกขยายโดย ActiveRecord :: Base class User < ActiveRecord::Base
Green

18

attr_accessorเป็นรหัสทับทิมและใช้เมื่อคุณไม่มีคอลัมน์ในฐานข้อมูลของคุณ แต่ยังต้องการแสดงเขตข้อมูลในแบบฟอร์มของคุณ วิธีเดียวที่จะอนุญาตให้ทำเช่นนี้คือattr_accessor :fieldnameและคุณสามารถใช้ฟิลด์นี้ในมุมมองหรือโมเดลของคุณหากคุณต้องการ แต่ส่วนใหญ่ในมุมมองของคุณ

ลองพิจารณาตัวอย่างต่อไปนี้

class Address
    attr_reader :street
    attr_writer :street  
    def initialize
        @street = ""
    end
end

ที่นี่เราได้ใช้attr_reader( อ่านคุณสมบัติ ) และattr_writer( เขียนคุณลักษณะ ) สำหรับการเข้าถึงวัตถุประสงค์ แต่เราสามารถใช้ฟังก์ชันการทำงานเดียวกันattr_accessorได้ ในระยะสั้นattr_accessor ให้การเข้าถึงทั้งวิธี getter และ setter

ดังนั้นรหัสที่แก้ไขแล้วมีดังนี้

class Address
    attr_accessor :street  
    def initialize
        @street = ""
    end
end

attr_accessibleช่วยให้คุณแสดงรายการคอลัมน์ทั้งหมดที่คุณต้องการอนุญาตให้มีการมอบหมายจำนวนมาก ตรงกันข้ามกับสิ่งนี้attr_protectedซึ่งหมายความว่าฉันไม่ต้องการให้ใครก็ตามที่ได้รับอนุญาตให้มอบหมายให้ทำหน้าที่นี้ มากกว่าจะเป็นเขตข้อมูลในฐานข้อมูลของคุณที่คุณไม่ต้องการให้ใครก็ตามมาเยี่ยม กดไลค์ฟิลด์สถานะหรือไลค์


2
คุณกำลังบอกว่าถ้าฉันได้สร้างเขตข้อมูลในการโยกย้ายจากนั้นทำให้มันพร้อมใช้งานโดยใช้ attr_accessible ไม่จำเป็นต้องสร้างผู้ทะเยอทะยานและผู้ตั้งค่า? แต่ถ้าเขตข้อมูลไม่ได้อยู่ในฐานข้อมูลทำไม attr_accessible จึงไม่ทำหน้าที่เหมือน getter / setter หากฉันรวมบรรทัด "has_secure_password" แล้ว attr_accessible ก็เพียงพอที่จะอนุญาตให้ getter / setter เป็น: รหัสผ่านและ: password_confirmation แม้ว่าจะไม่ได้อยู่ในฐานข้อมูล สับสนมาก;)
tentimes

2

คำสองคำ:

attr_accessorคือgetter, setterวิธีการ ในขณะที่attr_accessibleจะกล่าวว่าคุณลักษณะเฉพาะสามารถเข้าถึงได้หรือไม่ แค่นั้นแหละ.


ฉันต้องการเพิ่มเราควรใช้พารามิเตอร์ที่แข็งแกร่งแทนattr_accessibleการป้องกันจากมวล asignment

ไชโย!


2

ภาพรวมความแตกต่างอย่างรวดเร็วและรัดกุม:

attr_accessorเป็นวิธีที่ง่ายในการสร้าง access และอ่านและเขียนในชั้นเรียนของคุณ มันถูกใช้เมื่อคุณไม่มีคอลัมน์ในฐานข้อมูลของคุณ แต่ยังต้องการแสดงเขตข้อมูลในแบบฟอร์มของคุณ ฟิลด์นี้เป็น “virtual attribute”รูปแบบ Rails

คุณลักษณะเสมือน - แอตทริบิวต์ที่ไม่สอดคล้องกับคอลัมน์ในฐานข้อมูล

attr_accessible ใช้ในการระบุคุณสมบัติที่สามารถเข้าถึงได้โดยวิธีการควบคุมของคุณทำให้คุณสมบัติพร้อมใช้งานสำหรับการมอบหมายจำนวนมาก .. มันจะอนุญาตให้เข้าถึงคุณลักษณะที่คุณระบุเท่านั้นปฏิเสธส่วนที่เหลือ

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