ActiveModel :: ForbiddenAttributesError при создании нового пользователя


223

У меня есть эта модель в Ruby, но он бросает ActiveModel::ForbiddenAttributesError

class User < ActiveRecord::Base
  attr_accessor :password
  validates :username, :presence => true, :uniqueness => true, :length => {:in => 3..20}
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, :uniqueness => true, format: { with: VALID_EMAIL_REGEX }

  validates :password, :confirmation => true
  validates_length_of :password, :in => 6..20, :on => :create

  before_save :encrypt_password
  after_save :clear_password

  def encrypt_password
    if password.present?
      self.salt = BCrypt::Engine.generate_salt
      self.encrypted_password= BCrypt::Engine.hash_secret(password, salt)
    end
  end

  def clear_password
    self.password = nil
  end
end

когда я запускаю это действие

  def create
    @user = User.new(params[:user])
    if @user.save
      flash[:notice] = "You Signed up successfully"
      flash[:color]= "valid"
    else
      flash[:notice] = "Form is invalid"
      flash[:color]= "invalid"
    end
    render "new"
  end

на ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux].

Подскажите, пожалуйста, как избавиться от этой ошибки или создать правильную форму регистрации пользователя?


2
попробуйте добавить attr_accessible: password,: password_confirmation,: user_name,: email,: your-other-attribute в модели пользователя
Bachan Smruty

1
Добавьте гем strong_parameter для использования attr_accessible .
Венбинг Ли

сильные параметры использовать attr_accessible ?!
Тим Нгуен

1
Я считаю, что @BruceLi имел в виду: добавить protected_attributesдрагоценный камень для использования attr_accessible.
Стефан Магнусон

Ответы:


398

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

Возможно, вы захотите сделать это так:

class UsersController < ApplicationController

  def create
    @user = User.new(user_params)
    # ...
  end

  private

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

2
Есть ли документация о том, почему это работает или зачем это нужно?
DiverseAndRemote.com

20
@OmarJackman Функциональность предоставлена strong_parameterжемчужиной. Он описан в Руководствах по Rails: guides.rubyonrails.org/… .
Домон

21
Люди могут испытывать это, если они используют CanCan с Rails 4.0. Попробуйте довольно чистое обходное решение AntonTrapps, пока CanCan не будет обновлен.
mjnissim

@mjnissim Не могли бы вы опубликовать это как отдельный ответ? Я пропустил это в первый раз, но это все равно сэкономило мне кучу времени.
Пол Петтенгилл

64

Для тех, кто использует CanCan . Люди могут испытывать это, если они используют CanCan с Rails 4+ . Попробуйте AntonTrapps в довольно чистое решение обходного пути здесь до тех пор , пока CanCan обновляется:

В ApplicationController:

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

и в контроллере ресурсов (например, NoteController):

private
def note_params
  params.require(:note).permit(:what, :ever)
end

Обновить:

Вот продолжение проекта для CanCan под названием CanCanCan , которое выглядит многообещающим:

CanCanCan


1
Спасибо!! У меня вопрос, с CanCanCan (активный) решен или не нужен этот код?
Адриано Резенди

Для меня CanCanCan все еще имеет проблему. Не использование load_resourceили использование load_resource :except => :createрешило проблему. Проверьте оригинальный ответ здесь
Tun

24

Существует более простой способ избежать Strong Parameters, вам просто нужно преобразовать параметры в обычный хеш, как:

unlocked_params = ActiveSupport::HashWithIndifferentAccess.new(params)

model.create!(unlocked_params)

Конечно, это побеждает назначение сильных параметров, но если вы находитесь в ситуации, подобной моей (я делаю свое собственное управление разрешенными параметрами в другой части моей системы), это сделает работу.


Не работает в рельсах 6, исключение:unable to convert unpermitted parameters to hash
Тайлер

20

Если вы используете ActiveAdmin, не забудьте, что в блоке регистрации модели также есть allow_params:

ActiveAdmin.register Api::V1::Person do
  permit_params :name, :address, :etc
end

Они должны быть установлены вместе с таковыми в контроллере:

def api_v1_person_params
  params.require(:api_v1_person).permit(:name, :address, :etc)
end

В противном случае вы получите ошибку:

ActiveModel::ForbiddenAttributesError

18

Для тех, кто использует CanCanCan :

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

Для этого :createдействия CanCan попытается инициализировать новый экземпляр с продезинфицированным вводом, посмотрев, будет ли ваш контроллер реагировать на следующие методы (по порядку):

  1. create_params
  2. <model_name>_params например article_params (это соглашение по умолчанию в rails для именования вашего метода param)
  3. resource_params (метод с общим именем, который вы можете указать в каждом контроллере)

Кроме того, load_and_authorize_resourceтеперь можно использовать param_methodопцию, чтобы указать пользовательский метод в контроллере для запуска для очистки ввода.

Вы можете связать param_methodопцию с символом, соответствующим имени метода, который будет вызван:

class ArticlesController < ApplicationController
  load_and_authorize_resource param_method: :my_sanitizer

  def create
    if @article.save
      # hurray
    else
      render :new
    end
  end

  private

  def my_sanitizer
    params.require(:article).permit(:name)
  end
end

источник: https://github.com/CanCanCommunity/cancancan#33-strong-parameters


3

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


0

Если вы находитесь на Rails 4 и получаете эту ошибку, это может произойти, если вы используете enumмодель, если вы определили с символами, подобными этим:

class User
  enum preferred_phone: [:home_phone, :mobile_phone, :work_phone]
end

Форма передаст, скажем, радио-селектор как строковый параметр. Вот что случилось в моем случае. Простое решение состоит в том, чтобы заменить enumстроки вместо символов

enum preferred_phone: %w[home_phone mobile_phone work_phone]
# or more verbose
enum preferred_phone: ['home_phone', 'mobile_phone', 'work_phone']
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.