【问题标题】:ActiveModel::ForbiddenAttributesError when creating new userActiveModel::ForbiddenAttributesError 创建新用户时
【发布时间】:2013-06-24 11:49:46
【问题描述】:

我在 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].

您能告诉我如何消除此错误或建立正确的用户注册表单吗?

【问题讨论】:

  • 尝试在用户模型中添加 attr_accessible :password, :password_confirmation,:user_name, :email, :your-other-attributes
  • 添加 strong_parameter gem 以使用 attr_accessible
  • 使用attr_accessible的强参数?!
  • 我相信@BruceLi 的意思是:添加protected_attributes gem 以使用attr_accessible

标签: ruby-on-rails rails-activerecord


【解决方案1】:

还有一个原因是您通过一种方法覆盖了permitted_params。例如

def permitted_params
   params.permit(:email, :password)
end

【讨论】:

    【解决方案2】:

    对于那些使用 CanCanCan 的人:

    如果 CanCanCan 找不到正确的 params 方法,您将收到此错误。

    对于:create 操作,CanCan 将通过查看您的控制器是否会响应以下方法(按顺序)来尝试使用经过净化的输入来初始化一个新实例:

    1. create_params
    2. &lt;model_name&gt;_params 如article_params(这是 Rails 中用于命名参数方法的默认约定)
    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

    【讨论】:

    • 谢谢。这是我的问题。我重构了一个模型,但将 params 方法保留为旧名称。重命名并修复了问题。
    • 谢谢。这救了我?
    【解决方案3】:

    如果您在 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']
    

    【讨论】:

      【解决方案4】:

      有一种更简单的方法可以完全避免强参数,您只需将参数转换为常规哈希,如下所示:

      unlocked_params = ActiveSupport::HashWithIndifferentAccess.new(params)
      
      model.create!(unlocked_params)
      

      这当然违背了强参数的目的,但如果你处于像我这样的情况(我正在我系统的另一部分中自己管理允许的参数),这将完成工作。

      【讨论】:

      • 在 Rails 6 中不起作用,异常:unable to convert unpermitted parameters to hash
      【解决方案5】:

      对于那些使用 CanCan 的人。如果将 CanCanRails 4+ 一起使用,人们可能会遇到这种情况。尝试AntonTrapps's 相当干净的解决方法here 直到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

      【讨论】:

      • 谢谢!!我有一个问题,CanCanCan (active) 解决了还是不需要这个代码?
      • 对我来说,CanCanCan 仍然存在问题。不使用load_resource 或使用load_resource :except =&gt; :create 解决了这个问题。查看原答案here
      【解决方案6】:

      如果使用 ActiveAdmin,不要忘记模型寄存器块中还有一个 permit_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
      

      【讨论】:

        【解决方案7】:

        您也可以使用Protected Attributes gem,但这违背了要求强参数的目的。但是,如果您要升级较旧的应用程序,受保护的属性确实提供了一种简单的升级途径,直到您可以将 attr_accessible 重构为强参数。

        【讨论】:

          【解决方案8】:

          我猜你使用的是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
          

          【讨论】:

          • 是否有任何文件说明为什么这样做或为什么需要这样做?
          • @OmarJackman 该功能由strong_parameter gem 提供。它包含在 Rails 指南中:guides.rubyonrails.org/….
          • 如果人们在 Rails 4.0 中使用 CanCan,他们可能会遇到这种情况。在 CanCan 更新之前,请尝试 AntonTrapps's 相当干净的解决方法。
          • @mjnissim 您能否将此作为单独的答案发布?我第一次错过了它,但它仍然为我节省了大量时间。
          猜你喜欢
          • 2016-12-12
          • 1970-01-01
          • 2016-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多