Rails4: как разрешить хэш с динамическими ключами в params?

Я делаю запрос http put со следующими параметрами:

{"post" = > {"files" = > {"file1" => " file_content_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: файл1, файл2 - динамические ключи

11 ответов


по дизайну сильные параметры не позволяют хэши с динамическими ключами в качестве значений, поэтому.. в этом случае вам нужно белый files вручную.

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

в rails 5.1.2 это работает сейчас:

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

см https://github.com/rails/rails/commit/e86524c0c5a26ceec92895c830d1355ae47a7034


Я понимаю, что это старый пост. Тем не менее, поиск Google привел меня к этому результату, и я хотел поделиться своими выводами:

вот альтернативное решение, которое я нашел, что работает (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 уровнем динамических ключей. Принятый ответ позволяет множественные глубины.

[Edit] полезный совет от комментарий

" О, и вам нужно проверить, что params [: post][.files] существует, иначе ключи не будут работать"


ответ Орландо работает, но результирующий набор параметров возвращает false С permitted? метод. Также неясно, как вы будете действовать, если позже у вас будут другие параметры в post - хэш, который вы хотите включить в результат.

вот еще один способ

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

вот что мы должны были сделать в 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

вот еще один способ обойти это:

  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: {...} }


вы можете использовать временную переменную для создания разрешенного списка следующим образом:

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

вот простой способ сделать это (работает для 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

    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

Я не мог получить ни один из многих предложенных ответов на работу (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

в моем случае, был только один атрибут, который имел динамические ключи,

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