ActiveModel :: ForbiddenAttributesError al crear un nuevo usuario

223

Tengo este modelo en Ruby pero arroja un 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

cuando ejecuto esta acción

  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

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

¿Puede decirme cómo deshacerse de este error o establecer un formulario de registro de usuario adecuado?

LeMike
fuente
2
intente agregar attr_accessible: contraseña,: contraseña_confirmación,: nombre_usuario,: ​​correo electrónico,: sus-otros-atributos en el modelo de Usuario
Bachan Smruty
1
Agregue la gema strong_parameter para usar attr_accessible .
Wenbing Li
parámetros fuertes para usar attr_accessible ?!
Thiem Nguyen
1
Creo que @BruceLi quiso decir: Agregar la protected_attributesgema para usar attr_accessible.
Stefan Magnuson el

Respuestas:

398

Supongo que está utilizando Rails 4. Si es así, los parámetros necesarios se deben marcar como necesarios.

Es posible que desee hacerlo así:

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
fuente
2
¿Existe alguna documentación sobre por qué esto funciona o por qué es necesario?
DiverseAndRemote.com
20
@OmarJackman La funcionalidad es proporcionada por la strong_parametergema. Está cubierto en Guías de rieles: guides.rubyonrails.org/… .
Domon el
21
Las personas podrían estar experimentando esto si usan CanCan con Rails 4.0. Pruebe la solución alternativa bastante limpia de AntonTrapps hasta que CanCan se actualice.
mjnissim
@mjnissim ¿Podría publicar esto como una respuesta por separado? La perdí la primera vez, pero aún así me ahorró un montón de tiempo.
Paul Pettengill
64

Para aquellos que usan CanCan . Las personas podrían experimentar esto si usan CanCan con Rails 4+ . Pruebe la solución de solución bastante limpia de AntonTrapps aquí hasta que CanCan se actualice:

En el ApplicationController:

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

y en el controlador de recursos (por ejemplo, NoteController):

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

Actualizar:

Aquí hay un proyecto de continuación para CanCan llamado CanCanCan , que parece prometedor:

CanCanCan

mjnissim
fuente
1
¡¡Gracias!! Tengo una pregunta, con CanCanCan (activo) está resuelto o no necesita este código?
Adriano Resende
Para mí, CanCanCan todavía tiene el problema. No usar load_resourceo usar load_resource :except => :createresolvió el problema. Comprueba la respuesta original aquí
Tun
24

Hay una manera más fácil de evitar los Parámetros Fuertes, solo necesita convertir los parámetros a un hash regular, como:

unlocked_params = ActiveSupport::HashWithIndifferentAccess.new(params)

model.create!(unlocked_params)

Por supuesto, esto anula el propósito de los parámetros fuertes, pero si se encuentra en una situación como la mía (estoy haciendo mi propio manejo de los parámetros permitidos en otra parte de mi sistema), esto hará el trabajo.

Wilker Lucio
fuente
No funciona en los rieles 6, excepción:unable to convert unpermitted parameters to hash
Tyler
20

Si usa ActiveAdmin, no olvide que también hay una permit_params en el bloque de registro del modelo:

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

Estos deben configurarse junto con los del controlador:

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

De lo contrario, obtendrá el error:

ActiveModel::ForbiddenAttributesError
StuR
fuente
18

Para aquellos que usan CanCanCan :

Recibirá este error si CanCanCan no puede encontrar el método de parámetros correcto .

Para la :createacción, CanCan intentará inicializar una nueva instancia con entrada desinfectada al ver si su controlador responderá a los siguientes métodos (en orden):

  1. create_params
  2. <model_name>_params como article_params (esta es la convención predeterminada en rails para nombrar su método param)
  3. resource_params (un método con nombre genérico que podría especificar en cada controlador)

Además, load_and_authorize_resourceahora puede tomar una param_methodopción para especificar un método personalizado en el controlador que se ejecutará para desinfectar la entrada.

Puede asociar la param_methodopción con un símbolo correspondiente al nombre de un método que se llamará:

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

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

Andreas
fuente
3

Alternativamente, puede usar la gema Atributos protegidos , sin embargo, esto anula el propósito de requerir parámetros fuertes. Sin embargo, si está actualizando una aplicación anterior, los Atributos protegidos proporcionan una vía fácil para actualizar hasta el momento en que pueda refactorizar attr_accessible a params fuertes.

Brian Dear
fuente
0

Si está en Rails 4 y obtiene este error, podría suceder si está utilizando enumel modelo si lo ha definido con símbolos como este:

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

El formulario pasará, por ejemplo, un selector de radio como un parámetro de cadena. Eso es lo que sucedió en mi caso. La solución simple es cambiar enuma cadenas en lugar 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
fuente