Почему я получаю сильные ошибки параметров в Rails Console в rails 5?

Я хочу назвать это в моей консоли (ap это удивительная жемчужина печати):

ap Purchase.last(10)

но я получаю эту ошибку:

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

Это работает так:

irb(main):020:0> ap Purchase.last
#<Purchase:0x00007f86b792a320> {
                              :id => 28445,
                         :user_id => 10177,
                      :product_id => nil,
                    :product_type => nil,
                           :price => 9.0,
                    :gateway_code => nil,
                     :gateway_msg => nil,
                :gateway_response => nil,
                      :created_at => Fri, 18 May 2018 22:20:10 UTC +00:00,
                      :updated_at => Fri, 18 May 2018 22:20:10 UTC +00:00,
                  :checkout_total => 9.0,
                      :successful => true,
                         :cart_id => 17242,
                   :report_errors => nil,
    :transacted_value_of_products => 9.0,
            :comp_credits_applied => 0.0
}

И без ap как это:

irb(main):022:0> Purchase.last(10)
D, [2018-05-25T20:58:54.692575 #70552] DEBUG -- :   Purchase Load (0.5ms)  SELECT  "purchases".* FROM "purchases" ORDER BY "purchases"."id" DESC LIMIT $1  [["LIMIT", 10]]
+-------+---------+------------+-------------+-------+-------------+-------------+-------------+-------------+--------------+-------------+------------+---------+-------------+-------------+-------------+
| id    | user_id | product_id | product_... | price | gateway_... | gateway_msg | gateway_... | created_at  | updated_at   | checkout... | successful | cart_id | report_e... | transact... | comp_cre... |
+-------+---------+------------+-------------+-------+-------------+-------------+-------------+-------------+--------------+-------------+------------+---------+-------------+-------------+-------------+
| 28436 | 10471   |            |             | 5.0   |             | Completed   | {"mc_gro... | 2018-05-... | 2018-05-1... | 5.0         | true       | 17228   | {}          | 5.0         | 0.0         |
| 28437 | 9754    |            |             | 1.99  |             | Completed   | {"mc_gro... | 2018-05-... | 2018-05-1... | 2.48        | true       | 15273   | {}          | 1.99        | 0.0         |
| 28438 | 10472   |            |             | 9.0   |             |             | {\n  "id... | 2018-05-... | 2018-05-1... | 9.0         | true       | 17231   | {}          | 9.0         | 0.0         |
| 28439 | 10348   |            |             | 9.0   |             |             |             | 2018-05-... | 2018-05-1... | 9.0         | true       | 17235   |             | 9.0         | 0.0         |

Но не с аргументом и ap

irb(main):021:0> ap Purchase.last(3)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
    from (irb):21

Оказывается, я ничего не могу сделать:

irb(main):023:0> ap Purchase.find(28444)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
    from (irb):23

irb(main):024:0> ap Purchase.find(28444).gateway_response
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
    from (irb):24

В чем дело?

1 ответ

Решение

Что происходит и почему

ActionController::Parameters (который является то, что params работает в контроллерах) используется для наследования от HashWithIndifferentAccess который наследует от Hash, Так ActionController::Parameters < Hash Раньше было правдой, как если бы что-то вроде:

params.require(:x).permit(some_hash: %i[key1 key2]).is_a? Hash

Если бы вы копали Hash снаружи params:

some_hash = params.require(:x).permit(some_hash: ...)

и сериализовать это в модели:

class M < ApplicationRecord # Or ActiveRecord::Base in the past
  serialize :h, Hash
end
#...
m.h = some_hash

в вашей базе данных может получиться что-то вроде YAML:

--- !ruby/object:ActionController::Parameters
...

а не ожидаемый простой хэш YAMLized.

Но тогда Rails5 приходит и ActionController::Parameters больше не наследует отHash:

  • Делать ActionController::Parameters больше не наследует от HashWithIndifferentAccess,

и звонит to_h или же to_hash на ActionController::Parameters Теперь возникает исключение.

Если вы обновите свой код и попытаетесь загрузить модель с сериализованными данными:

serialize :h, Hash

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

Что с этим делать

Есть пара вещей, которые вам нужно сделать:

  1. Исправьте ваши контроллеры, чтобы убедиться, что они получают реальные хэши из params,
  2. Исправьте ваши данные так, чтобы вы использовали сериализованные хеши, а не ActionController::Parameters экземпляров.

Исправление контроллеров является простым делом вызова to_unsafe_h на параметры, которые еще не настоящие хэши.

Исправление данных уродливее. Я бы, вероятно, просмотрел таблицы, используя низкоуровневый интерфейс базы данных (т.е. нигде не ActiveRecord), читал YAML из каждой строки, YAML.load это, преобразовать его в хеш, вызывая to_unsafe_h на нем, а затем писать обратно the_real_hash.to_yaml текст. Вы могли бы использовать like '--- !ruby/object:ActionController::Parameters%' фильтруйте в предложении WHERE, чтобы иметь дело только с разбитыми строками.

Я также настоятельно рекомендую вам прекратить использование serialize пока ты там. serialize это немного клудж, и в базе данных нет нормального способа работы с YAML; теперь в этом нет особой необходимости, поскольку и PostgreSQL, и MySQL имеют встроенную поддержку JSON (но я не уверен, насколько хорошо ActiveRecord поддерживает JSON MySQL).

Другие вопросы по тегам