Я использую Rails 5.0.0.1
Мы хотели, чтобы пустая строка была опцией в enum
в одной из наших моделей. После нескольких дней работы в производственном процессе, обнаружив, что что-то было не так и отладив проблему, мы обнаружили: экземпляр этой модели обновлял свой столбец каждый раз, когда код проверял его достоверность (то есть !@model
и !!@model
). Это было вызвано наличием пары ключей в перечислении с ключом, являющимся пустой строкой {'': 0, 'good': 1}
.
Первоначально предполагалось преобразовать пустую строку в nil {'': nil, 'good':1}
(что-то не так в потребителе API, который отправляет пустую строку, и мы не хотим его сохранять). После проверки проблемы мы поняли значение nil в хэше enum не является проблемой, только пустая строка в одном из ее ключей .
Теперь, когда мы знаем, что ошибка существует, мы найдем обходной путь. Однако мы хотим знать, почему это происходило, поскольку при создании модели, проверке ее достоверности или в другом месте кода не было ошибок.
Я обнаружил эту похожую ошибку , но речь идет о validates_associated
и Foo.create
, объяснение проблемы не дано.
Шаги для воспроизведения
Создание модели с целочисленным столбцом rails g model Example my_enum:integer
class CreateExamples < ActiveRecord::Migration[5.0]
def change
create_table :examples do |t|
t.integer :my_enum
t.timestamps
end
end
end
Укажите столбец my_enum
как enum
в модели:
class Example < ApplicationRecord
enum my_enum: { '': 0, good: 1}
end
Создайте его экземпляр с помощью my_enum = 'good'
и проверьте его истинность
@model = Example.new
@model.my_enum = 'good'
@model.save
@model.my_enum # => 'good'
# so far so good
# the model works as expected if restarting console,
# finding it with Example.first, and so on...
!@model # For some unknown reason updates my_enum to nil
# Expected behavior: to return false
# Actual behavior: updates my_enum and returns true
Повторите ту же настройку и проверьте с помощью bang bang !!
, столбец также будет обновлен до nil
.
!!@model # Updates my_enum to nil
# Expected behavior: to return true
# Actual behavior: updates my_enum to nil and returns false
# Note that @model being an instance should evaluate to true
Это запрос, выполненный после выполнения !@model
или !!@model
(0.2ms) BEGIN
SQL (0.4ms) UPDATE "examples" SET "my_enum" = $1, "updated_at" = $2 WHERE "examples"."id" = $3 [["my_enum", nil], ["updated_at", 2018-11-01 13:50:50 UTC], ["id", 1]]
(2.8ms) COMMIT
Почему это происходит? Исправлена ли ошибка в других версиях rails? Какой будет лучшим решением? Разве вы не ожидаете того же поведения, что и мы? Если бы это работало как ожидалось, мы бы проигнорировали все пустые строки, теперь нам может понадобиться before_save: prevent_empty_in_my_enum
.
Возможно полезная информация:
ActiveRecord::Base.connection.select_value('SELECT version()')
(1.7ms) SELECT version()
=> "PostgreSQL 9.5.7 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4, 64-bit"