在Rails 4中遇到了一个之前需要使用attr_accessible的情况,会出现禁止属性错误(Forbidden Attributes Error)。

44

随着最近对Rails 4的升级,使用类似以下代码来更新属性将不起作用,并会出现ActiveModel::ForbiddenAttributes错误:

由于新版Rails默认启用了Strong Parameters,需要在控制器中指定参数名才能接受参数。要解决这个问题,需要在控制器中添加参数白名单,例如:

def article_params
  params.require(:article).permit(:title, :content)
end

然后,可以使用更新属性的代码:

@article.update(article_params)
@user.update_attributes(params[:user], :as => :admin)

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

attr_accessible :role_ids, :as =>admin
# or any attribute other than :role_ids contained within :user

在Rails 4中,您如何执行相同的任务?

5个回答

42
Rails 4现在默认内置了strong_parameters gem中的功能。
现在不再需要调用:as => :admin,也不需要在模型中使用attr_accessible :user_attribute, :as => admin。原因是,默认情况下,rails应用程序现在对模型上的每个属性都有“安全性”。您必须permit要访问/修改的属性。
现在,您只需要在update_attributes期间调用permit即可。
@user.update_attributes(params[:user], permit[:user_attribute])

或者,更准确地说:
@user.update_attributes(params[:user].permit(:role_ids))

然而,这一行代码允许任何用户修改被允许的角色。你必须记住只允许管理员或其他所需角色通过另一个过滤器(如下面的过滤器)访问此操作:

authorize! :update, @user, :message => 'Not authorized as an administrator.'

如果您正在使用Devise和CanCan进行身份验证和授权,则该方法将起作用。


39

如果您创建了一个新的Rails 4网站,您会注意到生成的控制器现在包括一个私有方法,您可以使用它来接收您经过消毒处理的params参数。这是一种不错的惯用语,看起来像这样:

private

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

允许批量赋值的旧方法是使用以下方式:

attr_accessible :username, :email, :password

为了标记某些参数可访问,您需要在模型上使用params方法来重构控制器以升级。但这可能比您现在能够处理的工作还要多。

另一种选择是使用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


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

不需要对代码进行任何修改即可运行
从这里获取:https://github.com/ryanb/cancan/issues/835#issuecomment-18663815


1
非常有帮助,如果没有这个的话可能会浪费好几个小时。 - cevaris
1
这对我有用,但我没有使用cancan,只用了devise。 - Luke Rohde

5
不要忘记将新的user_params方法添加到控制器操作中:
  def create
    @user = User.new(user_params)

    @user.save
    redirect_to 'wherever'
  end

-2
def create
  @user = User.create(user_params)
  ....
end

def update
  @user = User.find(params[:id])
  if @user.update_attributes(blog_params)
    redirect_to home_path, notice:  "Your profile has been successfully updated."
  else
    render action: "edit"
  end
end

private
  def user_params
    params.require(:user).permit(:name, :age, :others)
  end

@pixelearth,如果您知道原因,请告诉我 :) - Maged Makled
请解释他为什么需要这样做。 - stringRay2014
你的blog_params在哪里? - Miguel Peniche

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接