Разница между attr_accessor и attr_accessible

235

В Rails какая разница между attr_accessorи attr_accessible? Насколько я понимаю, использование attr_accessorиспользуется для создания методов получения и установки для этой переменной, так что мы можем получить доступ к переменной как Object.variableили Object.variable = some_value.

Я читал, что attr_accessibleделает эту конкретную переменную доступной для внешнего мира. Может кто-нибудь, пожалуйста, скажите мне, в чем разница

Феликс
источник
4
Вы правы в том, что attr_accessorиспользуется для генерации методов получения и установки. Пожалуйста, смотрите мой ответ на предыдущий вопрос для довольно подробного объяснения attr_accessible: stackoverflow.com/questions/2652907/… затем обновите свой вопрос, если вам понадобятся какие-либо другие конкретные детали после этого.
mikej
2
attr_accessible больше не поддерживается в Rails 4, если вы не используете гем protected_attributes, как указано в главном ответе на stackoverflow.com/questions/17371334/… (июль 2014 г.)
emery

Ответы:

258

attr_accessorэто метод Ruby, который делает геттер и сеттер. attr_accessibleэто метод Rails, который позволяет передавать значения в массовое присваивание: 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
Хлоя
19
Похоже, у Rails4 появился новый способ делать вещи. Смотрите этот ответ: stackoverflow.com/questions/17371334/…
Пол Рубел
1
Поскольку сильный параметр должен заменить использование attr_accessible edgeguides.rubyonrails.org/…
Имран Ахмад
173

Многие пользователи в этой теме и в Google очень хорошо объясняют, что attr_accessibleуказывает белый список атрибутов, которые разрешено обновлять массово ( все атрибуты объектной модели одновременно ). Это главным образом (и только) для защиты вашего приложения. из "Массового задания" пиратский подвиг.

Это объясняется здесь на официальном Rails doc: Mass Assignment

attr_accessorкод ruby ​​для быстрого создания методов установки и получения в классе. Вот и все.

Теперь в качестве объяснения не хватает того, что когда вы каким-либо образом создаете связь между моделью (Rails) с таблицей базы данных, вам НИКОГДА, НИКОГДА, НИКОГДА не нужно attr_accessorв вашей модели создавать сеттеры и геттеры, чтобы иметь возможность изменять ваши записи таблицы.

Это связано с тем, что ваша модель наследует все методы ActiveRecord::Baseкласса, который уже определяет для вас основные средства доступа CRUD (Create, Read, Update, Delete). Это объясняется в официальном документе здесь Rails Model и здесь Overwriting accessor по умолчанию (прокрутите вниз до главы «Перезаписать accessor по умолчанию»)

Скажем, например, что: у нас есть таблица базы данных с именем «users», которая содержит три столбца «firstname», «lastname» и «role»:

Инструкции SQL:

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

Я предположил, что вы установили опцию config.active_record.whitelist_attributes = trueв вашем config / environment / production.rb для защиты вашего приложения от эксплойта с массовыми назначениями. Это объясняется здесь: массовое назначение

Ваша модель Rails будет отлично работать с моделью ниже:

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

Теперь, чтобы облегчить вашу жизнь, вы не хотите делать сложный контроллер для вашей модели User. Таким образом, вы будете использовать attr_accessibleспециальный метод в вашей модели класса:

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

Вы не добавили атрибуты "role" в attr_accessibleсписок, потому что вы не позволяете своим пользователям самим устанавливать свою роль (например, admin). Вы делаете это самостоятельно на другом специальном админском View.

Хотя ваше представление пользователя не отображает поле «роль», пират может легко отправить HTTP-запрос POST, включающий «роль» в хэш params. Отсутствующий атрибут "role" в файле attr_accessibleпредназначен для защиты вашего приложения от этого.

Вы по-прежнему можете изменять свой атрибут user.role самостоятельно, как показано ниже, но не со всеми атрибутами вместе.

@user.role = DEFAULT_ROLE

Какого черта вы бы использовали attr_accessor?

Ну, это было бы в случае, если ваша пользовательская форма показывает поле, которое не существует в вашей таблице пользователей в виде столбца.

Например, скажем, в вашем пользовательском представлении отображается поле «пожалуйста, скажите администратору, что я здесь». Вы не хотите хранить эту информацию в вашей таблице. Вы просто хотите, чтобы 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 для переменной экземпляра с тем же именем. Так что это эквивалентно

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 и добавить элемент в форму, чтобы отправить поле зарплаты. Они могут использовать встроенный curl для отправки нового оклада в метод обновления контроллера, они могут создать скрипт, который отправляет сообщение с этой информацией.

Речь attr_accessorидет о создании методов для хранения переменных и attr_accessibleо безопасности массовых назначений.

Джошуа Чик
источник
2
У вас есть опечатка, после блока кода она должна сказатьattr_accesible
Чубас
Отлично пишите, мне нравится пример класса. Дополнительные (поддельные) бонусные баллы за включение объяснения :as!
Ян Воан,
Модель расширена ActiveRecord :: Base. class User < ActiveRecord::Base
Зеленый
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 предоставляет доступ как к методам получения, так и к методам установки.

Таким образом, модифицированный код, как показано ниже

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

attr_accessibleпозволяет вам перечислить все столбцы, которые вы хотите разрешить массовое назначение. Противоположность этому attr_protectedозначает, что в этом поле я НЕ хочу, чтобы кому-либо было разрешено массовое назначение. Скорее всего, это будет поле в вашей базе данных, с которым вы не хотите, чтобы кто-то возился. Как поле состояния или тому подобное.

shrikant1712
источник
2
Итак, вы говорите, что если я создал поля в миграции, а затем сделал их доступными с помощью attr_accessible, нет необходимости создавать геттер и сеттер? Но если поле отсутствует в базе данных, почему attr_accessible не действует как метод получения / установки? Если я добавлю строку «has_secure_password», то attr_accessible станет достаточно, чтобы позволить getter / setter: password и: password_confirmation, даже если их нет в базе данных. Очень смущен;)
10
2

В двух словах:

attr_accessorэто getter, setterметод. тогда как attr_accessibleсказать, что определенный атрибут доступен или нет. Это оно.


Я хочу добавить, что мы должны использовать параметр Strong вместо того, attr_accessibleчтобы защищать от массового присвоения.

Ура!

Маниш Шривастава
источник
2

Быстрый и краткий обзор различий:

attr_accessorэто простой способ создать средства чтения и записи в вашем классе. Он используется, когда у вас нет столбца в базе данных, но вы все еще хотите показать поле в ваших формах. Это поле “virtual attribute”в модели Rails.

виртуальный атрибут - атрибут, не соответствующий столбцу в базе данных.

attr_accessible используется для идентификации атрибутов, доступных вашим методам контроллера, делает свойство доступным для массового назначения. Он разрешает доступ только к указанным вами атрибутам, отрицая остальное.

Мухаммед Явар Али
источник