Rails:如何允许参数中包含动态键的哈希?

问题描述 投票:0回答:13

我使用以下参数发出 http put 请求:

{“帖子”=>{“文件”=>{“文件1”=>“文件内容_1”, “file2”=>“file_content_2”}},“id”=>“4”}

我需要在我的代码中允许哈希数组。 基于手册我已经尝试过这样的:

> params.require(:post).permit(:files) # does not work
> params.require(:post).permit(:files => {}) # does not work, empty hash as result
> params.require(:post).permit! # works, but all params are enabled

如何正确制作?

UPD1:file1、file2 - 是动态键

ruby-on-rails strong-parameters
13个回答
85
投票

Rails 5.1+

params.require(:post).permit(:files => {})

轨道5

params.require(:post).tap do |whitelisted|
  whitelisted[:files] = params[:post][:files].permit!
end

Rails 4 及以下

params.require(:post).tap do |whitelisted|
  whitelisted[:files] = params[:post][:files]
end

49
投票

在 Rails 5.1.2 中,现在可以使用:

params.require(:post).permit(:files => {})

参见https://github.com/rails/rails/commit/e86524c0c5a26ceec92895c830d1355ae47a7034


18
投票

我知道这是一篇旧帖子。然而,谷歌搜索给我带来了这个结果,我想分享我的发现:

这是我发现可行的替代解决方案(Rails 4):

params = ActionController::Parameters.new({"post"=>{"files"=>{"file1"=>"file_content_1", "file2"=>"file_content_2"}}, "id"=>"4"})
params.require(:post).permit(files: params[:post][:files].keys)
# Returns: {"files"=>{"file1"=>"file_content_1", "file2"=>"file_content_2"}}

此答案与已接受的答案之间的区别在于,此解决方案将参数限制为仅 1 级动态键。接受的答案允许多个深度。

[编辑]评论中的有用提示

“哦,您需要验证 params[:post][.files] 是否存在,否则密钥将失败”


6
投票

Orlando 的答案有效,但生成的参数集从

false
方法返回
permitted?
。此外,如果您稍后要在结果中包含
post
哈希中的其他参数,也不清楚您将如何进行。

还有另一种方法

permitted_params = params.require(:post).permit(:other, :parameters)
permitted_params.merge(params[:post][:files])

5
投票

这是我们在 Rails 5.0.0 中必须做的事情,希望这对某人有帮助。

files = params[:post].delete(:files) if params[:post][:files]
params.require(:post).permit(:id).tap do |whitelisted|
  whitelisted[:files] = files.permit!
end

3
投票

就我而言,只有一个属性具有动态键,

def post_params
  marking_keys = Set.new
  params[:post][:marking].keys.collect {|ii| marking_keys.add(ii)}
  params.require(:post).permit(:name, marking: marking_keys.to_a)
end

2
投票

您可以使用临时变量来构建允许的列表,如下所示:

permitted = params.require(:post).permit(:id)
permitted[:post][:files] = params[:post][:files].permit!

1
投票

这是解决这个问题的另一种方法:

  def post_params
    permit_key_params(params[:post]) do
      params.require(:post)
    end
  end

  def permit_key_params(hash)
    permitted_params = yield
    dynamic_keys = hash.keys
    dynamic_keys.each do |key|
      values = hash.delete(key)
      permitted_params[key] = values if values
    end
    permitted_params
  end

这应该适用于

post: { something: {...}, something_else: {...} }


1
投票

这是一个简单的方法(适用于 Rails 5):

  def my_params
    data_params = preset_data_params

    params.require(:my_stuff).permit(
      :some,
      :stuff,
      data: data_params
    )
  end

  def preset_data_params
    return {} unless params[:my_stuff]
    return {} unless params[:my_stuff][:data]

    params[:my_stuff][:data].keys
  end

0
投票
    Send params as array type like name=date[]**strong text**
      def user_post
        dates = params[:date]
        #render json: { 'response' => params }
        i = 0
        dates.each do |date|
          locations = params['location_'+"#{i}"]
          user_names = params['user_'+"#{i}"]
          currency_rates = params['currency_'+"#{i}"]
          flags = params['flag_'+"#{i}"]
          j = 0
          locations.each do |location|
             User.new(user_name: user_names[j], currency_name: flags[j],
             currency_rate: currency_rates[j], currency_flag: flags[j], location: location).save
            j =+ 1
          end
          i =+ 1
        end
   def

0
投票

如果没有以下任何一个,我就无法获得许多建议的工作答案(Rails 5)中的任何一个:

  1. 提前知道所有哈希键,或者
  2. 通过允许任意参数,实际上否定了强参数的值。

我正在使用这个解决方案。
它使用标准的强参数装备来清理大部分参数, 并且 Hash 属性被显式添加回来。

# Assuming:
class MyObject < ApplicationRecord
  serialize :hash_attr as: Hash
  #...
end

# MyObjectsController method to filter params:
def my_object_params
  # capture the hashed attribute value, as a Hash
  hash_attr = params[:my_object] && params[:my_object][:hash_attr] ?
      params[my_object][:hash_attr].to_unsafe_h : {}
  # clean up the params
  safe_params = params.require(:my_object).permit(:attr1, :attr2) # ... etc
  # and add the hashed value back in
  safe_params.to_unsafe_h.merge hash_attr: hash_attr
end

0
投票

让我们使用更复杂的数据子集:

task: {
  code: "Some Task",
  enabled: '1',
  subtask_attributes: { 
    '1' => { field: 'something', rules: {length_10: true, phone: false, presence: false }} ,
    '2' => { field: 'another', rules: {length_10: true, phone: false, presence: false }} 
  }
}

所以我们将其发送给StrongParameters进行处理:

params = ActionController::Parameters.new({
  task: {
    code: "Some Task",
    enabled: '1',
    subtask_attributes: { 
     '1' => { field: 'something', rules: {length_10: true, phone: false, presence: false }} ,
     '2' => { field: 'another', rules: {length_10: true, phone: false, presence: false }} 
    }
  }
})

我们将无法在 Rails 4 的强参数中指定 :rules,因为它是数据的哈希值:

permitted = params.require(:task).permit(:code, :enabled, subtask_attributes: [:field, :rules])
Unpermitted parameter: rules
Unpermitted parameter: rules

如果您想将特定属性和数据哈希值集合列入白名单怎么办?接受的答案不会将指定的属性列入白名单。你必须这样做:

params.require(:task).permit(
    :code, :enabled,
    subtask_attributes: [:field, :rules],
)

# whitelist the validation rules hash
params.require(:task).tap do |whitelisted|
  params[:task][:subtask_attributes].each do |k,v|
    whitelisted[:subtask_attributes][k] = params[:task][:subtask_attributes][k]
    whitelisted.permit!
  end
end

在这里尝试了几种解决方案后,没有一个有效。仅上述适用于包含任意哈希数据的 has_many 关联中的嵌套属性。


0
投票

我知道这是一篇旧文章,是许多用不同方法更新序列化哈希字段的文章之一。我想我给出的版本是我通过拼凑一些方法偶然发现的。我将只使用我的应用程序。这是 Rails 7.0.4 和 Ruby 3.0。我也使用苗条模板。

我有一个应税模型,其中包含不同部门的半持续税率。所有商品均需缴纳销售税,但就我而言,酒类会增加额外税。 Taxable 表只有两个字段,其中

tax
是序列化的 JSON 字段。

create_table "taxables", force: :cascade do |t|
  t.date "date"
  t.string "tax"
  ...
end

如果更改或添加税款,我将添加新记录以反映在某个日期发生的更改。任何过去曾缴税的机票都将使用机票日期之前最早的记录。有什么新的都会有新的改变记录

Taxable 模型有一个常量,用于命名所有可能使用的税:

TaxesUsed = %w(sales county federal city liquor)

记录类似于:

[#<Taxable:0x0000000111c7bfc0
  id: 2,                   
  date: Sun, 01 Jan 2023,  
  tax: {"sales"=>"8.0", "county"=>"2.0", "federal"=>"0.0", "city"=>"0.0", "liquor"=>"3.0"} ...
 #<Taxable:0x0000000111c7b980
  id: 3,                   
  date: Fri, 01 Jan 2021,  
  tax: {"sales"=>"8.0", "county"=>"2.0", "federal"=>"0.0", "city"=>"0.0", "liquor"=>"4.0"}...
]

我最初有一个有效的方法,即从一些未经允许的参数创建哈希并更新记录。然后我发现提到使用

form_with
来描述税收字段,令我惊讶的是它有效!形式:

= form_with(model: @taxable) do |form|
 
  div
    = form.label :date, style: "display: block"
    = form.date_field :date

  div
    = form.label :tax, style: "display: block", class:"font-bold"
    = form.fields_for :tax do |tax|
      # @taxable.tax is the existing serialize tax hash or a new default hash
      - @taxable.tax.each do |k,v|
        div.flex.gap-2
          div.w-36.font-bold.text-right = k
          div
            = tax.text_field k, value:v
            
  div[class="#{btn_submit}"]
    = form.submit

我必须定义一个新的taxable_parmam,声明:tax是一个哈希

def taxable_params
  params.require(:taxable).permit(:date, :tax => {})
end

提交表格给我参数:

Parameters: {"authenticity_token"=>"[FILTERED]",
 "taxable"=>{"date"=>"2021-01-01", "tax"=>{"sales"=>"8.0",
 "county"=>"2.0", "federal"=>"0.0", "city"=>"0.0",
 "liquor"=>"4.0"}}, "commit"=>"Update Taxable", "id"=>"3"}

而且它有效!我忘记了

form_with
但这是一个简单的事情,你只需使用普通的 ol Rails 即可获得。

更新:我忘记了来自表单字段的内容是文本。我必须将参数获取到新的哈希值,更改浮点值(百分比)并使用新的哈希值进行更新

© www.soinside.com 2019 - 2024. All rights reserved.