Sự khác biệt giữa attr_accessor và attr_accessible


235

Trong Rails, sự khác biệt giữa attr_accessorvà là attr_accessiblegì? Từ sự hiểu biết của tôi, sử dụngattr_accessor được sử dụng để tạo các phương thức getter và setter cho biến đó, để chúng ta có thể truy cập vào biến như Object.variablehoặc Object.variable = some_value.

Tôi đọc nó attr_accessiblelàm cho biến cụ thể đó có thể truy cập được ra thế giới bên ngoài. Ai đó có thể vui lòng cho tôi biết sự khác biệt


4
Bạn đúng attr_accessorđược sử dụng để tạo các phương thức getter và setter. Vui lòng xem câu trả lời của tôi cho câu hỏi trước để được giải thích khá toàn diện về attr_accessible: stackoverflow.com/questions/2652907/ và sau đó cập nhật câu hỏi của bạn nếu bạn cần bất kỳ chi tiết cụ thể nào khác sau đó.
mikej

2
attr_accessible không còn được hỗ trợ trong Rails 4 trừ khi bạn sử dụng đá quý được bảo vệ, theo câu trả lời hàng đầu cho stackoverflow.com/questions/17371334/ ((tháng 7 năm 2014)
emery

Câu trả lời:


258

attr_accessorlà một phương thức Ruby tạo ra một getter và setter. attr_accessiblelà một phương thức Rails cho phép bạn truyền các giá trị cho một phép gán khối lượng: new(attrs)hoặcupdate_attributes(attrs) .

Đây là một nhiệm vụ lớn:

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

Bạn có thể tưởng tượng rằng đơn đặt hàng cũng có thể có mã giảm giá :price_off. Nếu bạn không gắn thẻ :price_offkhi attr_accessiblebạn ngăn chặn mã độc có thể làm như vậy:

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

Ngay cả khi biểu mẫu của bạn không có trường cho :price_off, nếu trong mô hình của bạn, nó có sẵn theo mặc định. Điều này có nghĩa là một POST thủ công vẫn có thể thiết lập nó. Sử dụng attr_accessibledanh sách trắng những thứ có thể được chỉ định hàng loạt.


2
Tại sao không có attr_accessibletrong tài liệu Rails? api.rubyonrails.org
Chloe

19
Có vẻ như Rails4 có một cách mới để làm mọi thứ. Xem câu trả lời này: stackoverflow.com/questions/17371334/ từ
Paul Rubel

1
Bởi vì tham số mạnh đã thay thế việc sử dụng attr_accessible edgeguides.rubyonrails.org/ Kẻ
Imran Ahmad

173

Nhiều người trên chủ đề này và trên google giải thích rất rõ rằng attr_accessiblechỉ định danh sách trắng các thuộc tính được phép cập nhật hàng loạt ( tất cả các thuộc tính của một mô hình đối tượng cùng một lúc ) Điều này chủ yếu (và duy nhất) để bảo vệ ứng dụng của bạn từ "phân công hàng loạt" khai thác hải tặc.

Điều này được giải thích ở đây trên tài liệu Rails chính thức: Bài tập lớn

attr_accessorlà một mã ruby ​​để (nhanh chóng) tạo các phương thức setter và getter trong Class. Đó là tất cả.

Bây giờ, điều còn thiếu như một lời giải thích là khi bạn tạo bằng cách nào đó một liên kết giữa mô hình (Rails) với bảng cơ sở dữ liệu, bạn KHÔNG BAO GIỜ, KHÔNG BAO GIỜ, KHÔNG BAO GIỜ, KHÔNG BAO GIỜ attr_accessor trong mô hình của mình để tạo setters và getters để có thể sửa đổi bảng ghi chép.

Điều này là do mô hình của bạn kế thừa tất cả các phương thức từ ActiveRecord::BaseLớp, đã xác định các trình truy cập CRUD cơ bản (Tạo, Đọc, Cập nhật, Xóa) cho bạn. Điều này được giải thích trên tài liệu chính thức ở đây Rails Model và tại đây Ghi đè bộ truy cập mặc định (cuộn xuống chương "Ghi đè bộ truy cập mặc định")

Ví dụ: chúng tôi có một bảng cơ sở dữ liệu gọi là "người dùng" chứa ba cột "tên đầu tiên", "tên cuối" và "vai trò":

Hướng dẫn SQL:

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

Tôi giả sử rằng bạn đặt tùy chọn config.active_record.whitelist_attributes = true trong cấu hình / môi trường / sản xuất.rb của bạn để bảo vệ ứng dụng của bạn khỏi khai thác phân công hàng loạt. Điều này được giải thích ở đây: Bài tập lớn

Mô hình Rails của bạn sẽ hoạt động hoàn hảo với Mô hình ở đây bên dưới:

class User < ActiveRecord::Base

end

Tuy nhiên, bạn sẽ cần cập nhật riêng từng thuộc tính của người dùng trong bộ điều khiển để Chế độ xem biểu mẫu của bạn hoạt động:

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

Bây giờ để giảm bớt cuộc sống của bạn, bạn không muốn tạo một bộ điều khiển phức tạp cho mô hình Người dùng của mình. Vì vậy, bạn sẽ sử dụng attr_accessiblephương thức đặc biệt trong mô hình Lớp của mình:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname

end

Vì vậy, bạn có thể sử dụng "đường cao tốc" (phân công hàng loạt) để cập nhật:

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

Bạn đã không thêm các thuộc tính "vai trò" vào attr_accessibledanh sách vì bạn không để người dùng tự đặt vai trò của họ (như quản trị viên). Bạn tự làm điều này trên một View khác của quản trị viên đặc biệt.

Mặc dù chế độ xem người dùng của bạn không hiển thị trường "vai trò", một tên cướp biển có thể dễ dàng gửi yêu cầu POST HTTP bao gồm "vai trò" trong hàm băm params. Thuộc tính "vai trò" bị thiếu trên attr_accessiblelà để bảo vệ ứng dụng của bạn khỏi đó.

Bạn vẫn có thể tự sửa đổi thuộc tính user.role của mình như bên dưới, nhưng không phải với tất cả các thuộc tính cùng nhau.

@user.role = DEFAULT_ROLE

Tại sao bạn sẽ sử dụng địa ngục attr_accessor?

Chà, điều này sẽ xảy ra trong trường hợp biểu mẫu người dùng của bạn hiển thị một trường không tồn tại trong bảng người dùng của bạn dưới dạng cột.

Ví dụ: giả sử chế độ xem người dùng của bạn hiển thị trường "vui lòng cho biết quản trị viên rằng tôi đang ở đây". Bạn không muốn lưu trữ thông tin này trong bảng của bạn. Bạn chỉ muốn Rails gửi cho bạn một e-mail cảnh báo bạn rằng một người dùng "điên" ;-) đã đăng ký.

Để có thể sử dụng thông tin này, bạn cần lưu trữ tạm thời ở đâu đó. Điều gì dễ dàng hơn phục hồi nó trong một user.peekaboothuộc tính?

Vì vậy, bạn thêm trường này vào mô hình của bạn:

class User < ActiveRecord::Base

  attr_accessible :firstname, :lastname
  attr_accessor :peekaboo

end

Vì vậy, bạn sẽ có thể sử dụng có giáo dục user.peekaboo thuộc tính ở đâu đó trong bộ điều khiển của bạn để gửi e-mail hoặc làm bất cứ điều gì bạn muốn.

ActiveRecord sẽ không lưu thuộc tính "peekaboo" trong bảng của bạn khi bạn thực hiện user.savevì cô ấy không thấy bất kỳ cột nào khớp với tên này trong mô hình của mình.


48

attr_accessorlà một phương thức Ruby cung cấp cho bạn các phương thức setter và getter cho một biến thể hiện cùng tên. Vì vậy, nó tương đương với

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

attr_accessible là một phương thức Rails xác định các biến nào có thể được đặt trong một phép gán khối.

Khi bạn gửi một biểu mẫu và bạn có một cái gì đó như MyModel.new params[:my_model] sau đó bạn muốn kiểm soát nhiều hơn một chút, để mọi người không thể gửi những thứ mà bạn không muốn.

Bạn có thể làm attr_accessible :emailnhư vậy để khi ai đó cập nhật tài khoản của họ, họ có thể thay đổi địa chỉ email của họ. Nhưng bạn sẽ không làm thế attr_accessible :email, :salaryvì sau đó một người có thể thiết lập mức lương của họ thông qua việc nộp mẫu đơn. Nói cách khác, họ có thể hack theo cách của họ để tăng lương.

Đó là loại thông tin cần phải được xử lý rõ ràng. Chỉ cần loại bỏ nó khỏi hình thức là không đủ. Ai đó có thể đi vào với con bọ lửa và thêm yếu tố vào biểu mẫu để gửi trường lương. Họ có thể sử dụng curl tích hợp để gửi mức lương mới cho phương thức cập nhật bộ điều khiển, họ có thể tạo một tập lệnh gửi bài đăng với thông tin đó.

Vì vậy, attr_accessorvề việc tạo ra các phương thức để lưu trữ các biến và attr_accessiblevề bảo mật của các bài tập lớn.


2
Bạn có một lỗi đánh máy, sau khối mã nên nóiattr_accesible
Chubas

Tuyệt vời viết lên, tôi thích ví dụ lớp học. Điểm thưởng thêm (giả) bao gồm giải thích về :as!
Ian Vaughan

Mô hình được mở rộng bởi ActiveRecord :: Base. class User < ActiveRecord::Base
Green

18

attr_accessorlà mã ruby ​​và được sử dụng khi bạn không có cột trong cơ sở dữ liệu của mình, nhưng vẫn muốn hiển thị một trường trong biểu mẫu của bạn. Cách duy nhất để cho phép điều này là attr_accessor :fieldnamevà bạn có thể sử dụng trường này trong Chế độ xem hoặc mô hình của mình, nếu bạn muốn, nhưng chủ yếu là trong Chế độ xem của bạn.

Hãy xem xét ví dụ sau

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

Ở đây chúng tôi đã sử dụng attr_reader( thuộc tính có thể đọc được ) và attr_writer( thuộc tính có thể ghi ) cho mục đích truy cập. Nhưng chúng ta có thể đạt được chức năng tương tự bằng cách sử dụng attr_accessor. Nói tóm lại, attr_accessor cung cấp quyền truy cập vào cả hai phương thức getter và setter.

Vì vậy, mã sửa đổi là như dưới đây

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

attr_accessiblecho phép bạn liệt kê tất cả các cột bạn muốn cho phép Phân công hàng loạt. Trái ngược với điều này attr_protectedcó nghĩa là lĩnh vực này tôi KHÔNG muốn bất kỳ ai được phép tham gia Mass Assign. Nhiều khả năng nó sẽ là một lĩnh vực trong cơ sở dữ liệu của bạn mà bạn không muốn bất kỳ ai xung quanh. Giống như một trường trạng thái, hoặc tương tự.


2
Vì vậy, bạn đang nói rằng nếu tôi đã tạo các trường trong di chuyển, sau đó làm cho chúng có sẵn bằng cách sử dụng attr_accessible, thì không cần phải tạo getter và setter? Nhưng nếu trường không có trong cơ sở dữ liệu, tại sao attr_accessible không hoạt động như một getter / setter? Nếu tôi bao gồm một dòng "has_secure_password" thì attr_accessible trở nên đủ để cho phép getter / setter thành: password và: password_conf Confirmation mặc dù chúng không có trong cơ sở dữ liệu. Rất bối rối;)
dự kiến

2

Trong hai từ:

attr_accessorgetter, setterphương pháp. trong khi đó attr_accessiblecó thể nói rằng thuộc tính cụ thể có thể truy cập được hay không. đó là nó.


Tôi muốn thêm chúng ta nên sử dụng tham số Strong thay vì attr_accessibleđể bảo vệ khỏi sự sắp xếp hàng loạt.

Chúc mừng!


2

Tổng quan về sự khác biệt nhanh chóng và súc tích:

attr_accessorlà một cách dễ dàng để tạo các trình truy cập đọc và viết trong lớp của bạn. Nó được sử dụng khi bạn không có cột trong cơ sở dữ liệu của mình, nhưng vẫn muốn hiển thị một trường trong biểu mẫu của bạn. Trường này là một “virtual attribute”mô hình Rails.

thuộc tính ảo - một thuộc tính không tương ứng với một cột trong cơ sở dữ liệu.

attr_accessible được sử dụng để xác định các thuộc tính có thể truy cập bằng các phương thức điều khiển của bạn làm cho một thuộc tính có sẵn để gán khối lượng .. Nó sẽ chỉ cho phép truy cập vào các thuộc tính mà bạn chỉ định, từ chối phần còn lại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.