Різниця між attr_accessor і attr_accessible


235

У Rails, яка різниця між attr_accessorі attr_accessible? З мого розуміння, використовується attr_accessorвикористовується для створення методів getter та setter для цієї змінної, щоб ми могли отримати доступ до змінної, як Object.variableабо Object.variable = some_value.

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


4
Ви маєте рацію, що attr_accessorвикористовується для створення методів геттера та сетера. Будь ласка, дивіться мою відповідь на попереднє запитання щодо досить вичерпного пояснення attr_accessible: stackoverflow.com/questions/2652907/…, а потім оновіть своє запитання, якщо вам потрібні інші конкретні деталі після цього.
mikej

2
attr_accessible більше не підтримується в Rails 4, якщо ви не використовуєте gem protected_attributes, як зазначено у верхній відповіді на stackoverflow.com/questions/17371334/… (липень 2014 р.)
Emery

Відповіді:


258

attr_accessorце метод Рубі, який робить геттера і сеттера. 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: Mass Assignment

attr_accessorце рубіновий код для (швидкого) створення методів встановлення та отримання в Класі. Це все.

Тепер, чого не вистачає як пояснення, є те, що коли ви створюєте якимось чином зв’язок моделі (Rails) з таблицею баз даних, вам НІКОЛИ, НІКОЛИ, НІКОЛИ не потрібно attr_accessorу вашій моделі створювати сеттери та геттери, щоб мати змогу змінювати свої записи таблиці.

Це тому, що ваша модель успадковує всі методи від ActiveRecord::Baseкласу, який вже визначає базові CRUD-аксесуари (Створення, читання, оновлення, видалення) для вас. Це пояснюється в офіційному документі тут Rails Model і тут Перезапис аксесуара за замовчуванням (прокрутіть униз до розділу "Перезапис аксесуара за замовчуванням")

Скажімо, наприклад, що у нас є таблиця бази даних під назвою "користувачі", яка містить три стовпці "ім'я", "прізвище" та "роль":

Інструкції 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

Тепер, щоб полегшити ваше життя, ви не хочете робити складний контролер для вашої моделі користувача. Отже, ви будете використовувати 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-запит, який включає "роль" у хеш-парамах. Відсутній атрибут "роль" у програмі 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!
Ian Vaughan

Модель розширено 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 надає доступ до методів getter і setter.

Тож модифікований код наведений нижче

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

attr_accessibleдозволяє перелічити всі стовпці, до яких потрібно дозволити масове призначення. Протилежне до цього, це attr_protectedозначає, що це поле Я НЕ хочу, щоб хтось мав дозволити до масового призначення. Більш ніж ймовірно, це буде поле у ​​вашій базі даних, з яким ви не хочете, щоб хтось маніпулював. Як поле статусу тощо.


2
Так ви кажете, що якщо я створив поля під час міграції, а потім ставлю їх доступними за допомогою attr_accessible, не потрібно створювати геттер і сеттер? Але якщо поле відсутнє в базі даних, як прийти attr_accessible не діє як геттер / сетер? Якщо я включаю рядок "has_secure_password", тоді attr_accessible стає достатнім, щоб дозволити отримувачу / сеттеру: password та: password_confirmation, навіть якщо вони відсутні в базі даних. Дуже плутати;)
намети

2

У двох словах:

attr_accessorє getter, setterметод. тоді як attr_accessibleце означає, що конкретний атрибут доступний чи ні. Це воно.


Хочу додати, що ми повинні використовувати параметр Strong замість attr_accessibleзахисту від масового призначення.

Ура!


2

Швидкий і короткий огляд різниці:

attr_accessorце простий спосіб створення аксесуарів для читання та запису у вашому класі. Він використовується, коли у вашій базі даних немає стовпця, але все-таки потрібно показати поле у ​​ваших формах. Це поле є “virtual attribute”моделлю Rails.

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

attr_accessible використовується для ідентифікації атрибутів, доступних методами вашого контролера, робить властивість доступною для масового призначення. Це дозволить отримати доступ лише до атрибутів, які ви вказуєте, заперечуючи решта.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.