Perbedaan antara attr_accessor dan attr_accessible

235

Dalam Rails, apa perbedaan antara attr_accessordan attr_accessible? Dari pemahaman saya, menggunakan attr_accessordigunakan untuk membuat metode pengambil dan penyetel untuk variabel itu, sehingga kita dapat mengakses variabel seperti Object.variableatau Object.variable = some_value.

Saya membaca yang attr_accessiblemembuat variabel tertentu dapat diakses oleh dunia luar. Dapatkah seseorang tolong katakan padaku apa bedanya

felix
sumber
4
Anda benar yang attr_accessordigunakan untuk menghasilkan metode pengambil dan penyetel. Silakan lihat jawaban saya untuk pertanyaan sebelumnya untuk penjelasan yang cukup komprehensif tentang attr_accessible: stackoverflow.com/questions/2652907/… kemudian perbarui pertanyaan Anda jika Anda memerlukan detail spesifik lainnya setelah itu.
mikej
2
attr_accessible tidak lagi didukung di Rails 4 kecuali jika Anda menggunakan permata protected_attributes, sesuai jawaban teratas untuk stackoverflow.com/questions/17371334/… (Juli 2014)
amril

Jawaban:

258

attr_accessoradalah metode Ruby yang membuat pengambil dan penyetel. attr_accessibleadalah metode Rails yang memungkinkan Anda untuk mengirimkan nilai ke penugasan massal: new(attrs)atau update_attributes(attrs).

Inilah tugas massal:

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

Anda dapat membayangkan bahwa pesanan tersebut mungkin juga memiliki kode diskon, katakanlah :price_off. Jika Anda tidak memberi tag :price_offsaat attr_accessibleAnda menghentikan kode jahat agar dapat melakukannya seperti itu:

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

Bahkan jika formulir Anda tidak memiliki bidang untuk :price_off, jika dalam model Anda itu tersedia secara default. Ini berarti POST buatan masih bisa mengaturnya. Menggunakan attr_accessibledaftar putih hal-hal yang dapat ditugaskan secara massal.

Paul Rubel
sumber
2
Mengapa tidak ada attr_accessibledalam dokumentasi Rails? api.rubyonrails.org
Chloe
19
Sepertinya Rails4 memiliki cara baru untuk melakukan sesuatu. Lihat jawaban ini: stackoverflow.com/questions/17371334/…
Paul Rubel
1
Karena parameter yang kuat telah menggantikan penggunaan attr_accessible edgeguides.rubyonrails.org/...
Imran Ahmad
173

Banyak orang di utas ini dan di Google menjelaskan dengan sangat baik yang attr_accessiblemenentukan daftar putih atribut yang diizinkan untuk diperbarui secara massal ( semua atribut dari suatu model objek bersamaan pada saat yang sama ) Ini terutama (dan hanya) untuk melindungi aplikasi Anda dari eksploitasi bajak laut "penugasan massal".

Ini dijelaskan di sini di dokumen resmi Rails: Mass Assignment

attr_accessoradalah kode ruby ​​untuk (dengan cepat) membuat metode setter dan pengambil dalam suatu Class. Itu saja.

Sekarang, apa yang hilang sebagai penjelasan adalah bahwa ketika Anda membuat entah bagaimana tautan antara model (Rails) dengan tabel database, Anda TIDAK PERNAH, TIDAK PERNAH, TIDAK PERNAH perlu attr_accessordalam model Anda untuk membuat setter dan getter agar dapat memodifikasi Anda catatan tabel.

Ini karena model Anda mewarisi semua metode dari ActiveRecord::BaseKelas, yang sudah mendefinisikan aksesor CRUD dasar (Buat, Baca, Perbarui, Hapus) untuk Anda. Ini dijelaskan pada dokumen resmi di sini Rails Model dan di sini Menimpa akseptor default (gulir ke bawah ke bab "Timpa accessor default")

Katakan misalnya bahwa: kami memiliki tabel database yang disebut "pengguna" yang berisi tiga kolom "nama depan", "nama belakang" dan "peran":

Instruksi SQL:

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

Saya berasumsi bahwa Anda menetapkan opsi config.active_record.whitelist_attributes = truedi config / environment / production.rb Anda untuk melindungi aplikasi Anda dari eksploitasi penugasan massal. Ini dijelaskan di sini: Penugasan Massal

Model Rails Anda akan bekerja dengan baik dengan Model di bawah ini:

class User < ActiveRecord::Base

end

Namun Anda perlu memperbarui setiap atribut pengguna secara terpisah di controller Anda agar Tampilan formulir Anda berfungsi:

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

Sekarang untuk memudahkan hidup Anda, Anda tidak ingin membuat pengontrol yang rumit untuk model Pengguna Anda. Jadi Anda akan menggunakan attr_accessiblemetode khusus dalam model Kelas Anda:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Jadi, Anda dapat menggunakan "jalan raya" (penugasan massal) untuk memperbarui:

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

Anda tidak menambahkan atribut "peran" ke attr_accessibledaftar karena Anda tidak membiarkan pengguna mengatur sendiri peran mereka (seperti admin). Anda melakukannya sendiri di Tampilan admin khusus lain.

Meskipun tampilan pengguna Anda tidak menampilkan bidang "peran", bajak laut dapat dengan mudah mengirim permintaan HTTP POST yang menyertakan "peran" dalam hash params. Atribut "peran" yang hilang pada attr_accessibleadalah untuk melindungi aplikasi Anda dari itu.

Anda masih dapat memodifikasi atribut user.role Anda sendiri seperti di bawah ini, tetapi tidak dengan semua atribut secara bersamaan.

@user.role = DEFAULT_ROLE

Kenapa Anda akan menggunakan attr_accessor?

Nah, ini dalam kasus bahwa formulir pengguna Anda menunjukkan bidang yang tidak ada di tabel pengguna Anda sebagai kolom.

Misalnya, katakanlah tampilan pengguna Anda menunjukkan bidang "tolong-beri tahu admin bahwa saya di sini". Anda tidak ingin menyimpan info ini di tabel Anda. Anda hanya ingin Rails mengirimi Anda email yang memperingatkan Anda bahwa satu "gila" ;-) pengguna telah berlangganan.

Untuk dapat menggunakan informasi ini, Anda perlu menyimpannya sementara di suatu tempat. Apa yang lebih mudah daripada memulihkannya di user.peekabooatribut?

Jadi, Anda menambahkan bidang ini ke model Anda:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

Jadi Anda akan dapat menggunakan user.peekabooatribut yang terdidik di suatu tempat di controller Anda untuk mengirim email atau melakukan apa pun yang Anda inginkan.

ActiveRecord tidak akan menyimpan atribut "peekaboo" di tabel Anda ketika Anda melakukan user.savekarena dia tidak melihat kolom yang cocok dengan nama ini dalam modelnya.

Douglas
sumber
48

attr_accessoradalah metode Ruby yang memberi Anda metode penyetel dan pengambil ke variabel instan dengan nama yang sama. Jadi itu setara dengan

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

attr_accessible adalah metode Rails yang menentukan variabel apa yang dapat diatur dalam penugasan massal.

Ketika Anda mengirimkan formulir, dan Anda memiliki sesuatu seperti itu MyModel.new params[:my_model]maka Anda ingin memiliki sedikit lebih banyak kontrol, sehingga orang tidak dapat mengirimkan hal-hal yang tidak Anda inginkan.

Anda dapat melakukannya attr_accessible :emailsehingga ketika seseorang memperbarui akun mereka, mereka dapat mengubah alamat email mereka. Tetapi Anda tidak akan melakukannya attr_accessible :email, :salarykarena seseorang dapat menetapkan gajinya melalui pengajuan formulir. Dengan kata lain, mereka bisa meretas jalan mereka ke kenaikan gaji.

Informasi seperti itu perlu ditangani secara eksplisit. Hanya menghapusnya dari formulir tidak cukup. Seseorang bisa masuk dengan pembakar dan menambahkan elemen ke dalam formulir untuk mengirimkan bidang gaji. Mereka dapat menggunakan ikal bawaan untuk mengirim gaji baru ke metode pembaruan pengontrol, mereka dapat membuat skrip yang mengirimkan kiriman dengan informasi itu.

Begitu attr_accessorjuga tentang menciptakan metode untuk menyimpan variabel, dan attr_accessibletentang keamanan penugasan massal.

Joshua Cheek
sumber
2
Anda salah ketik, setelah blok kode seharusnya attr_accesible
tertulis
Tulisan bagus, saya suka contoh kelas. Poin bonus ekstra (palsu) untuk menyertakan penjelasan :as!
Ian Vaughan
Model diperpanjang oleh ActiveRecord :: Base. class User < ActiveRecord::Base
Hijau
18

attr_accessoradalah kode ruby ​​dan digunakan saat Anda tidak memiliki kolom di basis data Anda, tetapi masih ingin menampilkan bidang dalam formulir Anda. Satu-satunya cara untuk mengizinkan ini adalah dengan attr_accessor :fieldnamedan Anda dapat menggunakan bidang ini di Tampilan Anda, atau model, jika Anda inginkan, tetapi sebagian besar di View Anda.

Mari kita perhatikan contoh berikut ini

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

Di sini kita telah menggunakan attr_reader( atribut yang dapat dibaca ) dan attr_writer( atribut yang dapat ditulis ) untuk mengakses tujuan. Tetapi kita dapat mencapai fungsi yang sama menggunakan attr_accessor. Singkatnya, attr_accessor menyediakan akses ke metode pengambil dan penyetel.

Jadi kode yang dimodifikasi adalah seperti di bawah ini

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

attr_accessiblememungkinkan Anda untuk membuat daftar semua kolom yang Anda inginkan untuk memungkinkan Penugasan Massal. Kebalikan dari ini adalah attr_protectedyang berarti bidang ini saya TIDAK ingin ada orang yang diizinkan untuk Misa. Kemungkinan besar itu akan menjadi bidang dalam basis data Anda yang tidak Anda inginkan ada orang lain. Seperti bidang status, atau sejenisnya.

shrikant1712
sumber
2
Jadi, apakah Anda mengatakan bahwa jika saya telah membuat bidang dalam migrasi, kemudian membuatnya tersedia menggunakan attr_accessible, tidak perlu membuat pengambil dan penyetel? Tetapi jika bidang tidak ada dalam database, bagaimana bisa attr_accessible tidak bertindak seperti pengambil / penyetel? Jika saya memasukkan baris "has_secure_password" maka attr_accessible menjadi cukup untuk memungkinkan pengambil / penyetel ke: kata sandi dan: kata sandi: konfirmasi meskipun mereka tidak ada dalam basis data. Sangat bingung;)
tentimes
2

Dalam dua kata:

attr_accessoradalah getter, settermetode. sedangkan attr_accessibledikatakan atribut tertentu dapat diakses atau tidak. itu dia.


Saya ingin menambahkan kita harus menggunakan parameter Strong daripada attr_accessiblemelindungi dari penugasan massal.

Bersulang!

Manish Shrivastava
sumber
2

Ikhtisar perbedaan singkat & ringkas:

attr_accessoradalah cara mudah untuk membuat aksesor baca dan tulis di kelas Anda. Ini digunakan ketika Anda tidak memiliki kolom di database Anda, tetapi masih ingin menampilkan bidang di formulir Anda. Bidang ini adalah “virtual attribute”dalam model Rails.

atribut virtual - atribut yang tidak sesuai dengan kolom dalam database.

attr_accessible digunakan untuk mengidentifikasi atribut yang dapat diakses oleh metode controller Anda membuat properti tersedia untuk penugasan massal .. Ini hanya akan memungkinkan akses ke atribut yang Anda tentukan, menolak sisanya.

Muhammad Yawar Ali
sumber