Rails 4中的禁用属性错误遇到在早期版本的Rails中使用attr_accessible的情况

Ecn*_*lyr 39 ruby-on-rails attr-accessible activemodel strong-parameters ruby-on-rails-4

随着最近升级到Rails 4,使用类似下面的代码更新属性不起作用,我收到一个ActiveModel::ForbiddenAttributes错误:

@user.update_attributes(params[:user], :as => :admin)
Run Code Online (Sandbox Code Playgroud)

用户在模型中具有以下attr_accessible行:

attr_accessible :role_ids, :as =>admin
# or any attribute other than :role_ids contained within :user
Run Code Online (Sandbox Code Playgroud)

你如何在Rails 4中完成同样的任务?

Ecn*_*lyr 41

Rails 4现在具有默认内置的strong_parameters gem的功能.

一个人不再:as => :admin需要打电话,你也不需要attr_accessible :user_attribute, :as => admin你的模型.这样做的原因是,默认情况下,rails应用程序现在对模型上的每个属性都具有"安全性".您必须具有permit要访问/修改的属性.

您现在需要做的就是permitupdate_attributes以下时间打电话:

@user.update_attributes(params[:user], permit[:user_attribute])
Run Code Online (Sandbox Code Playgroud)

或者,更确切地说:

@user.update_attributes(params[:user].permit(:role_ids))
Run Code Online (Sandbox Code Playgroud)

但是,这一行允许任何用户修改permitted角色.您必须记住只允许管理员或任何其他所需角色通过另一个过滤器访问此操作,例如:

authorize! :update, @user, :message => 'Not authorized as an administrator.'
Run Code Online (Sandbox Code Playgroud)

...如果您使用Devise和CanCan进行身份验证和授权,这将有效.


sup*_*ary 35

如果您创建一个新的Rails 4站点,您会注意到生成的控制器现在包含一个私有方法,您可以使用它来接收已清理的参数.这是一个很好的习语,看起来像这样:

private

  def user_params
    params.require(:user).permit(:username, :email, :password)
  end
Run Code Online (Sandbox Code Playgroud)

允许大规模分配的旧方法是使用类似的东西:

attr_accessible :username, :email, :password
Run Code Online (Sandbox Code Playgroud)

在您的模型上将某些参数标记为可访问.

升级

升级你有几个选择.您最好的解决方案是使用params方法重构控制器.这可能比你现在有更多的工作时间.

Protected_attributes gem

另一种方法是使用protected_attributes gem来恢复attr_accessible方法.这使得升级路径稍微平滑,有一个主要的警告.

主要警告

在Rails 3中,任何没有attr_accessible调用的模型都允许所有属性.

在带有protected_attributes gem的Rails 4中,这种行为是相反的.任何没有attr_accessible调用的模型都会限制所有属性.您现在必须在所有模型上声明attr_accessible.这意味着,如果您还没有使用attr_accessible,则需要将其添加到所有模型中,这可能与创建params方法一样多.

https://github.com/rails/protected_attributes


Yav*_*rov 9

这个问题也可能是由Cancan gem引起的

只需添加到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
Run Code Online (Sandbox Code Playgroud)

没有任何进一步修改代码的工作从这里得到它:https://github.com/ryanb/cancan/issues/835#issuecomment-18663815


Hay*_*r87 5

不要忘记将新的 user_params 方法添加到控制器操作中:

  def create
    @user = User.new(user_params)

    @user.save
    redirect_to 'wherever'
  end
Run Code Online (Sandbox Code Playgroud)