2012年3月21日,星期三

强参数:在控制器而不是模型中处理质量分配

由 dhh 发布

我们正在探索一种在 Rails 中处理质量分配保护的新方法。实际上,这并不是一种全新的方法,它更像是一种将既定实践提炼出来,并加入一些“醋”以应对你可能忘记的情况。这种新方法将成为 Rails 4.0 的默认功能,但我们希望在正式发布之前得到您的帮助来测试和完善它。

强参数

这种新方法是 slice 模式 的提炼,我们称之为 strong_parameters 插件(也已 作为 gem 提供)。基本思想是将质量分配保护从模型移到控制器,而它本就属于那里。

控制器的整个目的是控制用户和应用程序之间的流程,包括身份验证、授权以及作为其中的一部分的访问控制。我们本不应该将质量分配保护放入模型中,而且很多人早已停止这样做,转而采用 slice 模式或其变体。现在是时候将这种模式提炼出来并推广给大家了。

示例

class PeopleController < ActionController::Base
  # This will raise an ActiveModel::ForbiddenAttributes exception because it's using mass assignment
  # without an explicit permit step.
  def create
    Person.create(params[:person])
  end
  
  # This will pass with flying colors as long as there's a person key in the parameters, otherwise
  # it'll raise a ActionController::MissingParameter exception, which will get caught by 
  # ActionController::Base and turned into that 400 Bad Request reply.
  def update
    redirect_to current_account.people.find(params[:id]).tap do |person|
      person.update_attributes!(person_params)
    end
  end
  
  private
    # Using a private method to encapsulate the permissible parameters is just a good pattern
    # since you'll be able to reuse the same permit list between create and update. Also, you
    # can specialize this method with per-user checking of permissible attributes.
    def person_params
      params.required(:person).permit(:name, :age)
    end
end

我们仍在调整 API,但它已经足够好用了。我已经用 strong_parameters 的 permit 方法替换了我们在新版 Basecamp 中使用的 slice 模式。

仍有工作要做

我们仍在努力寻找一种整洁的方式来处理嵌套参数,但已经有一个设计准备好实现,所以应该不会太远。此外,Yehuda 将致力于表单签名,这将减轻在标准 HTML 表单情况下手动声明允许参数的需要(您仍然需要手动允许参数以用于 API 和其他客户端)。

但现在它已经足够有用了。该插件目前仅完全兼容 rails/3-2-stable rev 275ee0dc7b 及更高版本,以及 rails/master rev b49a7ddce1 及更高版本,原因是存在一个关于包装参数的测试问题(如果您不为 JSON API 使用包装参数,则可以使用该插件与任何版本的 Rails 3.2 兼容)。