我的 Rails 模型中有一个序列化属性,并正在尝试更新它。
Block#preferences
属性首先作为文本类型通过迁移生成。我们使用 Postgresql 14。
# == Schema Information
#
# Table name: blocks
#
# id :bigint not null, primary key
# name :string
# preferences :text
# created_at :datetime not null
# updated_at :datetime not null
# page_id :bigint not null
#
class Block < ApplicationRecord
belongs_to :page
serialize :preferences, JSON
end
我知道强参数的全部意义在于不允许任意参数。但要问一个问题,如何允许通过序列化属性更新动态键而不记录
Unpermitted parameters
。
下面是传递给
update
操作的参数:
Parameters: {
"authenticity_token"=>"[FILTERED]",
"block"=>{
"title_text"=>"Hello world!",
"description_text"=>"Send us a message.",
"hero_image"=>"placeholder/block01.jpg",
"bg_color"=>"#652020"
},
"commit"=>"Update Block",
"id"=>"23"
}
这些在
preferences: {"title_text"=>"Rent with us", "description_text"=>"Send us a message.", "hero_image"=>"placeholder/block01.jpg", "bg_color"=>"#000000"}
对象上保存为 Block
。这些首选项属性只是一个示例 - 还有其他属性,例如 logo_text
和 links_alignment
。这个列表还在不断增长。
如果您将
update
属性指定为要更新的属性,则 preferences
操作将起作用。
def update
@block = Block.find(params[:id])
respond_to do |format|
if @block.update(preferences: params[:block])
end
end
end
private
def block_params
params.require(:block).permit(
:name,
:preferences
)
end
但是,如果我用
update
调用 block_params
,日志会显示该字段是不允许的:
Unpermitted parameters: :title_text, :description_text, :hero_image, :bg_color.
def update
@block = Block.find(params[:id])
respond_to do |format|
if @block.update(block_params)
end
end
end
private
def block_params
params.require(:block).permit(
:name,
:preferences
)
end
由于这在我们的环境中似乎有点新颖,因此我希望了解序列化如何能够从
params[:block]
映射首选项,但无法使用 update
调用 block_params
。预先非常感谢您的指导!
参数白名单几乎与您的架构或模型对数据的处理方式几乎无关。
ActionContoller::Parameters
只是一个类似于散列的对象,当您将其传递给 ActiveRecord 持久性方法(新建、创建、更新等)时,如果传递的参数实例没有设置其 permitted
标志,它将引发。这也适用于 ActionContoller::Parameters
的嵌套实例。
此外,Rails 还有一个
action_on_unpermitted_parameters
配置选项,如果存在未包含在白名单中的参数,它将记录或引发。
要完全禁用批量分配保护,您可以使用
permit!
:
def block_params
params.require(:block).permit!
end
这允许
ActionContoller::Parameters
实例的所有键以及任何嵌套参数。
如果您想要一个较少核的选项来处理具有任意键的哈希,您可以遍历键:
def block_params
params.require(:block).permit(*params[:block].keys)
end
这里的区别在于,这仅允许允许的标量值,而不是数组和散列。