Ошибка запрещенных атрибутов в Rails 4 при возникновении ситуации, когда в более ранних версиях Rails использовался attr_accessible

С недавним обновлением до Rails 4, обновление атрибутов с использованием кода, похожего на приведенный ниже, не работает, я получаю ActiveModel::ForbiddenAttributes ошибка:

@user.update_attributes(params[:user], :as => :admin)

Где пользователь имеет следующую строку attr_accessible в модели:

attr_accessible :role_ids, :as =>admin
# or any attribute other than :role_ids contained within :user

Как вы решаете ту же задачу в Rails 4?

5 ответов

Решение

В Rails 4 теперь есть возможности из встроенного по умолчанию гема strong_parameters.

Больше не нужно звонить :as => :adminи вам не нужно attr_accessible :user_attribute, :as => admin в твоей модели. Причина этого заключается в том, что по умолчанию приложения rails теперь имеют "безопасность" для каждого атрибута в моделях. Ты должен permit атрибут, к которому вы хотите получить доступ / изменить.

Все, что вам нужно сделать сейчас, это позвонить permit в течение update_attributes:

@user.update_attributes(params[:user], permit[:user_attribute])

или, если быть более точным:

@user.update_attributes(params[:user].permit(:role_ids))

Эта единственная строка, однако, позволяет любому пользователю изменять permitТед Роль. Не забудьте разрешить доступ к этому действию только администратору или любой другой желаемой роли через другой фильтр, такой как:

authorize! :update, @user, :message => 'Not authorized as an administrator.'

,,, который будет работать, если вы используете Devise и CanCan для аутентификации и авторизации.

Если вы создадите новый сайт Rails 4, вы заметите, что сгенерированные контроллеры теперь включают в себя закрытый метод, который вы используете для получения ваших очищенных параметров. Это хорошая идиома, и выглядит примерно так:

private

  def user_params
    params.require(:user).permit(:username, :email, :password)
  end

Старый способ разрешить массовое назначение состоял в том, чтобы использовать что-то вроде:

attr_accessible :username, :email, :password

на вашей модели, чтобы пометить определенные параметры как доступные.

модернизация

Для обновления у вас есть несколько вариантов. Лучшим решением будет рефакторинг ваших контроллеров методом params. Это может быть больше работы, чем у вас есть время сейчас.

Protected_attributes gem

Альтернативой может быть использование гема protected_attributes, который восстанавливает метод attr_accessible. Это делает более плавный путь обновления с одним серьезным предостережением.

Большая оговорка

В Rails 3 любая модель без вызова attr_accessible допускает все атрибуты.

В Rails 4 с гемом protected_attributes это поведение полностью изменено. Любая модель без вызова attr_accessible имеет все атрибуты с ограничениями. Теперь вы должны объявить attr_accessible на всех ваших моделях. Это означает, что если вы не использовали attr_accessible, вам нужно добавить это ко всем вашим моделям, что может быть такой же работой, как и просто создание метода params.

https://github.com/rails/protected_attributes

Эта проблема также может быть вызвана жемчужиной Канкан

Просто добавьте в application_controller.rb

before_filter do
  resource = controller_name.singularize.to_sym
  method = "#{resource}_params"
  params[resource] &&= send(method) if respond_to?(method, true)
end

Работает без каких-либо дальнейших изменений кода получил его здесь: https://github.com/ryanb/cancan/issues/835

Не забудьте добавить новый метод user_params в действие контроллера:

  def create
    @user = User.new(user_params)

    @user.save
    redirect_to 'wherever'
  end
def create
  @user = User.create(user_params)
  ....
end

def update
  @user = User.find(params[:id])
  if @user.update_attributes(blog_params)
    redirect_to home_path, notice:  "Your profile has been successfully updated."
  else
    render action: "edit"
  end
end

private
  def user_params
    params.require(:user).permit(:name, :age, :others)
  end
Другие вопросы по тегам