#ruby-on-rails
#ruby-on-rails
Вопрос:
Я использую стандартную форму rails для обновления ActiveRecord ::Store
store :settings, accessors: %i[is_public]
Моя форма выглядит так:
<%= form.select(:is_public, options_for_select([['True', true], ['False', false]])) %>
Когда я смотрю на сохраненный хэш, они были преобразованы в строки, есть ли способ сохранить логический тип здесь?
Комментарии:
1. Есть ли причина, по которой это не является истинным атрибутом (т. Е. Хранится в таблице)? Если это так, вы можете перезаписать документы доступа
2. Я просто пытаюсь сохранить все свои пользовательские настройки в одном столбце, а не иметь много столбцов для более чем 30 параметров настроек, есть ли лучший способ?
3. Нет, это нормально и теперь более понятно, но в этом случае я бы рекомендовал перезаписать средство доступа, как показано в документах.
4. Я создал пользовательский модуль для добавления методов перезаписи средства доступа, как предлагает @engineersmnky (см. Ниже).
Ответ №1:
Я смог написать модуль CustomStoreAccessor для перезаписи средства доступа для этих атрибутов:
module CustomStoreAccessor
def boolean_store_accessor(attr_name)
define_method "#{attr_name}=" do |value|
super(value=='true')
end
define_method attr_name do
super()=='true'
end
end
def integer_store_accessor(attr_name)
define_method "#{attr_name}=" do |value|
super(value.to_i)
end
define_method attr_name do
super().to_i
end
end
end
Затем это позволяет мне добавлять эти методы в мою модель:
class Client < ApplicationRecord
extend CustomStoreAccessor
store :settings_object, accessors: %i[is_public max_sessions]
boolean_store_accessor :is_public
integer_store_accessor :max_sessions
Комментарии:
1. поскольку ваши методы логически названы, я бы рекомендовал изменить
boolean_store_accessor
наsuper(value == 'true')
иsuper() == 'true'
соответственно, потому что, если это действительно должно быть логическим значением, я бы всегда ожидал логического значения. Такжеto_sym
in"#{attr_name}=".to_sym
не требуется, aString
вполне приемлемо2. Это действительно просто вызывает вопрос «Но почему?». Собственные типы JSON существуют уже много лет, и ваш драйвер преобразует логические значения и числа в столбцы JSON и из них без каких-либо этого.
Ответ №2:
Не использовать store
. Ему вообще нет места, кроме как в устаревших приложениях.
Хранение сериализованных данных в столбце varchar / text является полностью устаревшим подходом, поскольку ваша база данных почти наверняка имеет собственный тип JSON / JSONB, к которому на самом деле можно эффективно запрашивать, тогда как сериализованные данные либо не подлежат запросу, если они упорядочены Ruby или YAML, либо требуют от вас де-сериализации данных во время запроса, еслиоказывается, оно хранится в виде строки JSON.
Драйвер базы данных также автоматически сериализует / десериализует столбец. Использование store
или его двоюродного serialize
брата фактически «преобразует его в два раза», так что в итоге вы получите строки JSON вместо реальных значимых типов, таких как объекты и массивы.
Если вы хотите создать средства доступа для «атрибутов» в объекте JSON, используйте store_accessor
.
Комментарии:
1. Я хотел бы иметь возможность использовать столбец jsonb, но я должен был сказать, что причина, по которой я использую store, заключается в том, что я пытаюсь сохранить зашифрованный объект настроек, используя драгоценный камень lockbox. Пока мне не удалось заставить lockbox и JSON работать вместе. И lockbox говорит, что столбец должен быть текстовым. Есть ли лучший способ?
2. Это зависит от БД и требований — в Postgres вы можете использовать расширение pgcrypto вместе со столбцом bytea для шифрования «всего столбца» на стороне БД.