加入健壮参数功能后,Action Controller 的参数禁止在 Avtive Model 中批量赋值,除非参数在白名单中。也就是说,你要明确选择那些属性可以批量更新,避免意外把不该暴露的属性暴露了。
而且,还可以标记哪些参数是必须传入的,如果没有收到,会交由 raise/rescue
处理,返回“400 Bad Request”。
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::ParameterMissing exception, which will get
# caught by ActionController::Base and turned into that 400 Bad
# Request reply.
def
update
person = current_account.people.find(params[
:id
])
person.update!(person_params)
redirect_to person
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.require(
:person
).permit(
:name
,
:age
)
end
end
|
4.5.1 允许使用的标量值
假如允许传入 :id
:
params.permit(
:id
)
|
若 params
中有 :id
,且 :id
是标量值,就可以通过白名单检查,否则 :id
会被过滤掉。因此不能传入数组、Hash 或其他对象。
允许使用的标量类型有:String
、Symbol
、NilClass
、Numeric
、TrueClass
、FalseClass
、Date
、Time
、DateTime
、StringIO
、IO
、ActionDispatch::Http::UploadedFile
和 Rack::Test::UploadedFile
。
要想指定 params
中的值必须为数组,可以把键对应的值设为空数组:
params.permit(id: [])
|
要想允许传入整个参数 Hash,可以使用 permit!
方法:
params.require(
:log_entry
).permit!
|
此时,允许传入整个 :log_entry
Hash 及嵌套 Hash。使用 permit!
时要特别注意,因为这么做模型中所有当前属性及后续添加的属性都允许进行批量赋值。
4.5.2 嵌套参数
也可以允许传入嵌套参数,例如:
params.permit(
:name
, { emails: [] },
friends: [
:name
,
{ family: [
:name
], hobbies: [] }])
|
此时,允许传入 name
,emails
和 friends
属性。其中,emails
必须是数组;friends
必须是一个由资源组成的数组:应该有个 name
属性,还要有 hobbies
属性,其值是由标量组成的数组,以及一个 family
属性,其值只能包含 name
属性(任何允许使用的标量值)。
4.5.3 更多例子
你可能还想在 new
动作中限制允许传入的属性。不过此时无法再根键上调用 require
方法,因为此时根键还不存在:
# using `fetch` you can supply a default and use
# the Strong Parameters API from there.
params.fetch(
:blog
, {}).permit(
:title
,
:author
)
|
使用 accepts_nested_attributes_for
方法可以更新或销毁响应的记录。这个方法基于 id
和 _destroy
参数:
# permit :id and :_destroy
params.require(
:author
).permit(
:name
, books_attributes: [
:title
,
:id
, :_destroy])
|
如果 Hash 的键是数字,处理方式有所不同,此时可以把属性作为 Hash 的直接子 Hash。accepts_nested_attributes_for
和 has_many
关联同时使用时会得到这种参数:
# To whitelist the following data:
# {"book" => {"title" => "Some Book",
# "chapters_attributes" => { "1" => {"title" => "First Chapter"},
# "2" => {"title" => "Second Chapter"}}}}
params.require(
:book
).permit(
:title
, chapters_attributes: [
:title
])
|