ActiveModel :: ForbiddenAttributesError ao criar novo usuário

223

Eu tenho esse modelo em Ruby, mas lança um 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

quando eu executo essa ação

  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

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

Você pode me dizer como se livrar desse erro ou estabelecer um formulário de registro de usuário adequado?

LeMike
fonte
2
tente com a adição de attr_accessible: senha,: password_confirmation,: user_name,: e-mail,: o-outro-atributos no modelo User
Bachan Smruty
1
Adicione a gem strong_parameter para usar attr_accessible .
Wenbing Li
parâmetros fortes para usar attr_accessible ?!
Thiem Nguyen 21/01
1
Acredito que @BruceLi significava: adicione a protected_attributesgema para usar attr_accessible.
Stefan Magnuson

Respostas:

398

Eu acho que você está usando o Rails 4. Nesse caso, os parâmetros necessários devem ser marcados conforme necessário.

Você pode querer fazer assim:

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
Domon
fonte
2
Existe alguma documentação sobre por que isso funciona ou por que isso é necessário?
DiverseAndRemote.com
20
@OmarJackman A funcionalidade é fornecida pela strong_parametergema. Está coberto nos Guias do Rails: Guides.rubyonrails.org/… .
Domon
21
As pessoas podem estar passando por isso se usarem o CanCan com o Rails 4.0. Experimente a solução alternativa bastante limpa da AntonTrapps até o CanCan ser atualizado.
Mjnissim
@mjnissim Você poderia postar isso como uma resposta separada? Eu perdi a primeira vez, mas ainda me poupou uma tonelada de tempo.
Paul Pettengill
64

Para quem usa o CanCan . As pessoas podem estar passando por isso se usarem o CanCan com Rails 4+ . Experimente a solução alternativa bastante limpa da AntonTrapps aqui até o CanCan ser atualizado:

No ApplicationController:

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

e no controlador de recursos (por exemplo, NoteController):

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

Atualizar:

Aqui está um projeto de continuação para o CanCan chamado CanCanCan , que parece promissor:

CanCanCan

mjnissim
fonte
1
Obrigado!! Eu tenho uma pergunta, com CanCanCan (ativo) está resolvido ou não precisa desse código?
Adriano Resende
Para mim, o CanCanCan ainda tem o problema. Não usar load_resourceou usar load_resource :except => :createresolveu o problema. Verifique a resposta original aqui
Tun
24

Existe uma maneira mais fácil de evitar os parâmetros fortes, basta converter os parâmetros em um hash regular, como:

unlocked_params = ActiveSupport::HashWithIndifferentAccess.new(params)

model.create!(unlocked_params)

Isso derrota o propósito de parâmetros fortes, é claro, mas se você estiver em uma situação como a minha (estou fazendo meu próprio gerenciamento de parâmetros permitidos em outra parte do meu sistema), isso fará o trabalho.

Wilker Lucio
fonte
Não funciona nos trilhos 6, exceção:unable to convert unpermitted parameters to hash
Tyler
20

Se você estiver usando o ActiveAdmin, não esqueça que também há um allow_params no bloco de registro do modelo:

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

Eles precisam ser configurados juntamente com os do controlador:

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

Caso contrário, você receberá o erro:

ActiveModel::ForbiddenAttributesError
StuR
fonte
18

Para aqueles que usam CanCanCan :

Você receberá esse erro se o CanCanCan não conseguir encontrar o método correto de parâmetros .

Para a :createação, o CanCan tentará inicializar uma nova instância com entrada higienizada, verificando se o seu controlador responderá aos seguintes métodos (em ordem):

  1. create_params
  2. <model_name>_params como article_params (esta é a convenção padrão nos trilhos para nomear seu método param)
  3. resource_params (um método com nome genérico que você pode especificar em cada controlador)

Além disso, load_and_authorize_resourceagora você pode param_methodoptar por especificar um método personalizado no controlador para executar para limpar a entrada.

Você pode associar a param_methodopção a um símbolo correspondente ao nome de um método que será chamado:

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

fonte: https://github.com/CanCanCommunity/cancancan#33-strong-parameters

Andreas
fonte
3

Como alternativa, você pode usar a gema Atributos Protegidos , no entanto, isso anula o propósito de exigir parâmetros fortes. No entanto, se você estiver atualizando um aplicativo mais antigo, os Atributos Protegidos fornecem um caminho fácil para atualizar até o momento em que você pode refatorar o attr_accessible para parâmetros fortes.

Brian Dear
fonte
0

Se você estiver no Rails 4 e receber esse erro, poderá ocorrer se você estiver usando enumo modelo se tiver definido com símbolos como este:

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

O formulário passará, digamos, um seletor de rádio como um parâmetro de string. Foi o que aconteceu no meu caso. A solução simples é mudar enumpara strings em vez de símbolos

enum preferred_phone: %w[home_phone mobile_phone work_phone]
# or more verbose
enum preferred_phone: ['home_phone', 'mobile_phone', 'work_phone']
lacostenycoder
fonte