Rails 5: невозможно получить хеш-значения из параметра

Я столкнулся со странной проблемой.

undefined method `values' for #<ActionController::Parameters:0x007fb06f6b2728>

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

attributes = params[:line_item][:line_item_attributes_attributes] || {}
attributes.values

параметр выглядит так: хэш хэшей:

{"0"=>{"product_attribute_id"=>"4"}, "1"=>{"product_attribute_id"=>"7"}}

теперь, когда я делаю это в консоли и назначаю это переменным атрибутам, он работает безупречно. Поэтому я изо всех сил пытаюсь понять, что здесь не работает - и как заставить это работать.


person Sebastian Jennings Almnes    schedule 22.01.2016    source источник
comment
это действительно странно. Любой объект класса ActionController::Parameters должен отвечать на values. Какие у вас версии ruby ​​и rails? Не могли бы вы добавить logger.warn attributes.inspect?   -  person tillmo    schedule 22.01.2016


Ответы (4)


взгляните на это. Очень странно, поскольку ActionController::Parameters является подклассом Hash, вы можете преобразовать его непосредственно в хеш, используя метод to_h для хэша params.

Однако to_h будет работать только с параметрами из белого списка, поэтому вы можете сделать что-то вроде:

permitted = params.require(:line_item).permit(: line_item_attributes_attributes)
attributes = permitted.to_h || {}
attributes.values

Но если вместо этого вы не хотите вносить в белый список, вам просто нужно использовать метод to_unsafe_h.

Обновлять

Мне было очень интересно узнать об этой проблеме, поэтому я начал исследовать, и теперь, когда вы выяснили, что используете Rails 5, ну, это и есть причина этой проблемы, как сказал @tillmo в стабильных выпусках Rails, таких как 4.x, ActionController::Parameters — это подкласс Hash, поэтому он действительно должен реагировать на метод values, однако в Rails 5 ActionController::Parameters теперь возвращает Object вместо Hash

Примечание: это не влияет на доступ к ключам в хэше параметров, например params[:id]. Вы можете просмотреть Pull Request, в котором реализовано это изменение.

Для доступа к параметрам в объекте вы можете добавить to_h к параметрам:

params.to_h

Если мы посмотрим на метод to_h в ActionController::Parameters, мы увидим, что он проверяет, разрешены ли параметры, прежде чем преобразовывать их в хэш.

# actionpack/lib/action_controller/metal/strong_parameters.rb
def to_h
  if permitted?
    @parameters.to_h
  else
    slice(*self.class.always_permitted_parameters).permit!.to_h
  end
end

Например:

def do_something_with_params
  params.slice(:param_1, :param_2)
end

Что вернет:

{ :param_1 => "a", :param_2 => "2" }

Но теперь это вернет объект ActionController::Parameters.

Вызов to_h для этого вернет пустой хеш, потому что param_1 и param_2 не разрешены.

Чтобы получить доступ к параметрам из ActionController::Parameters, вам нужно сначала разрешить параметры, а затем вызвать to_h для объекта.

def do_something_with_params
  params.permit([:param_1, :param_2]).to_h
end

Вышеприведенное вернет хеш с только что разрешенными параметрами, но если вы не хотите разрешать параметры и хотите пропустить этот шаг, есть другой способ, используя метод to_unsafe_hash:

def do_something_with_params
  params.to_unsafe_h.slice(:param_1, :param_2)
end

Существует способ всегда разрешать параметры из конфигурации из application.rb, если вы хотите всегда разрешать определенные параметры, вы можете установить параметр конфигурации. Примечание: это вернет хэш со строковыми ключами, а не символьными ключами.

#controller and action are parameters that are always permitter by default, but you need to add it in this config.
config.always_permitted_parameters = %w( controller action param_1 param_2)

Теперь вы можете получить доступ к таким параметрам, как:

def do_something_with_params
  params.slice("param_1", "param_2").to_h
end

Обратите внимание, что теперь ключи являются строками, а не символами.

Надеюсь, это поможет вам понять корень вашей проблемы.

Источник: eileen.codes

person svelandiag    schedule 22.01.2016
comment
но этот класс, а именно ActionController::Parameters, является подклассом Hash, а последний имеет метод values. - person tillmo; 22.01.2016
comment
На самом деле нет, поэтому в этом классе есть метод to_h - person svelandiag; 22.01.2016
comment
попробуйте params = ActionController::Parameters.new; params.values, чтобы увидеть, что вам не нужно to_h здесь. - person tillmo; 22.01.2016
comment
ммм, это начинает обретать смысл... лол может быть связано с версией рельсов? - person svelandiag; 22.01.2016
comment
Я запускаю rails 5.0 beta1, пытался добавить .to_h к параметру, но это дает мне пустой хэш - person Sebastian Jennings Almnes; 22.01.2016
comment
это потому, что вам нужно внести параметры в белый список, пожалуйста, внимательно прочитайте ответ. Но вы по-прежнему можете использовать to_unsafe_h и не заносить в белый список. - person svelandiag; 22.01.2016
comment
Пожалуйста, проверьте ответ еще раз, теперь я нашел корень вашей проблемы. Надеюсь, это поможет вам - person svelandiag; 23.01.2016

Начиная с Rails 5, параметры относятся к классу ActionController::Parameters.

Если вы выполните params.to_h, вы получите следующую ошибку.

*** ActionController::UnfilteredParameters Exception: unable to convert 
unpermitted parameters to hash

Вы можете сделать следующее, чтобы разрешить все параметры и получить формат Hash:

parameters = params.permit(params.keys).to_h

Остерегайтесь использовать это! Вы разрешаете все параметры, которые могут включать неизвестные параметры, которые могут повредить ваш код.

person Abhi    schedule 24.08.2017

Я думаю, что происходит следующее:

В консоли вы работаете с простым хешем под названием attributes. В качестве хеша параметр attributes в консоли имеет a действительный метод экземпляра с именем values.

В вашем приложении rails хэш params больше не является простым хешем. Это экземпляр класса ActionController::Parameters. В качестве экземпляра этого класса у него нет метода экземпляра с именем values, но у него есть экземплярный метод с именем to_h & to_unsafe_h, который поможет достичь ваших целей. После вызова to_h для ваших параметров вы можете вызвать метод values.

person BigRon    schedule 22.01.2016
comment
но класс ActionController::Parameters является подклассом Hash, а последний имеет метод values. - person tillmo; 22.01.2016
comment
Точнее, попробуйте в консоли params = ActionController::Parameters.new({line_item: ActionController::Parameters.new({line_item_attributes_attributes: ActionController::Parameters.new})}); attributes = params[:line_item][:line_item_attributes_attributes] || {}; puts attributes.class; attributes.values - person tillmo; 22.01.2016
comment
правда... вы также можете просто запустить ActionController::Parameters.method_defined? :values, и вы увидите, что значения являются допустимым методом... теперь я в тупике - person BigRon; 22.01.2016
comment
@tillmo погружается в Ruby, хотя вы можете попробовать это с вашей переменной params: params.kind_of? Hash #=> true, но затем попробуйте params.instance_of? Hash #=> false Итак, params - это своего рода хеш, но не экземпляр хэша ... почему это может быть? - person BigRon; 22.01.2016
comment
Глядя на Rails 5, Parameters больше не наследуется от Hash (через HashWithIn DifferentAccess), но они добавили :values ​​в качестве метода делегата, поэтому он все еще должен работать... Вот Rails 5 code по сравнению с Rails 4 код - person BigRon; 22.01.2016
comment
Я действительно использую Rails 5, однако, когда я делаю attribute = params[:line_item][:line_item_attributes_attributes].to_h, он становится пустым хешем. - person Sebastian Jennings Almnes; 22.01.2016
comment
Вы должны вызывать to_h для безопасной версии параметров, т.е. my_params = params.permit(:line_item).require(:product_attribute_id), в основном везде, где вы внесли свои параметры в белый список в контроллере... в противном случае вам нужно вызвать to_unsafe_h для параметров... или вы, вероятно, можете запустить это: params.permit!.to_h, но это навсегда удалит ваш хэш параметров из белого списка, чего вы не должны хотеть... лучше работать с безопасной версией хэша параметров - person BigRon; 22.01.2016
comment
И... :values все еще должен работать, так как он был добавлен в качестве метода делегата в Rails 5. - person BigRon; 22.01.2016

Слово мудрому: если вы используете link_to_sorted из sorted гема, это ломает представления в Rails 5.

person okay56k    schedule 11.08.2017