«ПРЕДУПРЕЖДЕНИЕ. Невозможно массово назначить защищенные атрибуты» - PullRequest
67 голосов
/ 15 октября 2010

Я использовал методы RESTful для генерации модели (фактически я использую гем Devise, который делает это для меня), и я добавил в модель новые поля с именами first_name и last_name. Миграция прошла нормально. Я добавил attr_accessor: first_name,: last_name в модель и ожидал, что она будет работать. Но когда я пытаюсь массово назначить новые экземпляры с помощью Doctor.create ({: first_name => "MyName"}) и т. Д., Я получаю сообщения об ошибках, в которых я не могу массово назначить защищенные атрибуты.

Я думал, что весь смысл использования attr_accessor заключается в том, чтобы обойти защищенность полей модели. Можете ли вы помочь мне разобраться в этом сообщении?

Редактировать: о, и, кстати, записи тоже не создаются. Я думал, что они должны быть, так как это всего лишь предупреждение, но их нет в базе данных.

Edit2: вот моя модель

class Doctor < User
  has_many :patients
  has_many :prescriptions, :through=> :patients

  validates_presence_of :invitations, :on => :create, :message => "can't be blank"

  attr_accessor :invitations
end

и схема, которая не имеет имен first_name и last_name, поскольку они созданы в таблице пользователей, которая является предком врачей. Я использовал наследование одной таблицы.

create_table :doctors do |t|
  t.integer :invitations

  t.timestamps
end

и это миграция для изменения таблицы пользователей

add_column :users, :first_name, :string
add_column :users, :last_name, :string
add_column :users, :type, :string

РЕДАКТИРОВАТЬ: вот начальный файл. Я не включаю метод truncate_db_table, но он работает.

%w{doctors patients}.each do |m|
  truncate_db_table(m)  
end  

Doctor.create(:invitations=>5, :email=>"email@gmail.com", :first_name=>"Name", :last_name=>"LastName")
Patient.create(:doctor_id=>1, :gender=>"male", :date_of_birth=>"1991-02-24")

Ответы [ 6 ]

140 голосов
/ 15 октября 2010

Не путайте attr_accessor с attr_accessible.Accessor встроен в Ruby и определяет метод-получатель - model_instance.foo # returns something - и метод-установщик - model_instance.foo = 'bar'.

Accessible определяется Rails и делает атрибут массово-назначаемым (делает противоположное attr_protected).

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

12 голосов
/ 18 мая 2012

Чтобы небезопасно взломать ваше приложение, совершенно непригодное для производственного режима:

Перейдите в /config/application.rb Прокрутите вниз до конца, где вы найдете

{config.active_record.whitelist_attributes = true}

Установите значение false.

EDIT / btw (после 4 месяцев интенсивной работы с рубинами, включая 11-недельный семинар): DHH считает, что для новичков (его слова): "вверхи запуск "важнее, чем" очень безопасный ".

БУДУТ РЕКОМЕНДУЕТСЯ: Многие опытные разработчики рельсов очень увлечены тем, что не хочет, чтобы вы это делали.

ОБНОВЛЕНИЕ: 3 года спустя, еще один способ сделать это - опять же, небезопасно, но лучше, чем вышеупомянутое решение, вероятно, потому что вы должны сделать это для каждой модели

class ModelName < ActiveRecord::Base
  column_names.each do |col|
    attr_accessible col.to_sym
  end
  ...
end
2 голосов
/ 07 октября 2013

Добавьте attr_accessible : variable1, variable2 в файл маршрута таблицы.

2 голосов
/ 15 октября 2010

Не используйте attr_accessor здесь.ActiveRecord создает их автоматически на модели.Кроме того, ActiveRecord не будет создавать запись, если выдается ошибка проверки или массового назначения.

РЕДАКТИРОВАТЬ: вам не нужна таблица докторов, вам нужна таблица пользователей со столбцом типа для обработки Rails Наследование одной таблицы .Приглашения будут на столе пользователей.Ах, я вижу в добавленном вами примере кода у вас есть тип для пользователей.Избавьтесь от таблицы врачей, передайте приглашения пользователям, и я думаю, что с вами все будет в порядке.Также избавьтесь от attr_accessor.Не требуется.

Имейте в виду, что рельсы STI используют одну и ту же таблицу для всех классов и подклассов конкретной модели.Все ваши записи «Доктор» будут строками в таблице пользователей с типом «доктор»

РЕДАКТИРОВАТЬ: Кроме того, вы уверены, что хотите проверять только наличие приглашений при создании, а не обновления?

0 голосов
/ 11 июля 2019

Если вы хотите отключить защиту массового назначения для отдельного вызова (но не в глобальном масштабе), можно использовать параметр :without_protection => true.Я считаю это полезным для миграций и других мест, где ключи / значения хеш-кода жестко запрограммированы или, как известно, безопасны.

Пример здесь (также работает в рельсах 3.2): https://apidock.com/rails/v3.1.0/ActiveRecord/Base/create/class

0 голосов
/ 18 февраля 2014

Согласен с ответом @Robert Speicher Но я настоятельно рекомендую вам использовать Сильный параметр вместо attr_accessible для защиты от массового присвоения.

Приветствия!

...