前两天将项目中的 Rails 生到了 4.1.5,跑了测试发现有几个查询相关的用例抛出了 ActiveModel::ForbiddenAttributesError 的异常,这个异常大家很熟悉,是防止 Mass Assignment 而在 Rails 4 中引入的一种保护机制。但是常用在创建或更新对象的逻辑中,突然在查询相关逻辑中抛出这样的异常,还是有些莫名奇妙。
根据异常栈查看类 Rails 的源码,发现 4.1.5 where 查询确实进行了更新,新增了 opts = sanitize_forbidden_attributes(opts)
这步,而 sanitize_forbidden_attributes 本身就是 sanitize_for_mass_assignment 方法的别名。如下:
Rails 4.1.5
# https://github.com/rails/rails/blob/v4.1.5/activerecord/lib/active_record/relation/query_methods.rb#L563
def where!(opts = :chain, *rest) # :nodoc:
if opts == :chain
WhereChain.new(self)
else
if Hash === opts
opts = sanitize_forbidden_attributes(opts)
references!(PredicateBuilder.references(opts))
end
self.where_values += build_where(opts, rest)
self
end
end
# https://github.com/rails/rails/blob/v4.1.5/activemodel/lib/active_model/forbidden_attributes_protection.rb#L26
alias :sanitize_forbidden_attributes :sanitize_for_mass_assignment
Rails 4.1.4
# https://github.com/rails/rails/blob/v4.1.4/activerecord/lib/active_record/relation/query_methods.rb#L560
def where!(opts = :chain, *rest) # :nodoc:
if opts == :chain
WhereChain.new(self)
else
references!(PredicateBuilder.references(opts)) if Hash === opts
self.where_values += build_where(opts, rest)
self
end
end
根源找到了,就比较好修复。将原代码中的 conditions = params.slice(:ua, :sdk)
改为 conditions = params.permit(:ua, :sdk)
。其实两者的目的是一样的,防止用户自己构造表单查询本没有权限查看的内容。所以 Rails 也算是强制统一了读写操作中对 params 的限制措施。