Rails find_or_create_by добавить приведение к хеш-значению атрибута типа json? - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть модель со столбцом :extra_fields с типом данных :jsonb, я хочу добавить в столбец атрибуты хэшей attr, что-то вроде этого ниже, но я не уверен в синтаксисе для приведения типов данных значений хеш-значенийздесь, а если нет, то какова лучшая практика для приведения данных хеш-значения?

      instance = Model.find_or_create_by(ref_id: hash[:ref_id]) do |a|
          a.extra_fields = {

            'attr1' : hash[:attr1], <-- //possible to cast type here ie ::type ?
            'attr2' : hash[:attr2]  <--

          }
        instance.save!
      end

Бонус: как бы я прикинул значения хеш-типа как :decimal, :string, :boolean, :date например?

1 Ответ

0 голосов
/ 16 февраля 2019

Все входящие параметры в Rails / Rack являются строками.Ну, за исключением параметров массива / хеша, которые все еще имеют строки в качестве значений.Rails выполняет фактическое приведение при передаче параметров в модели.

Вы можете приводить строки к любому другому типу в Ruby с помощью методов .to_x:

irb(main):006:0> "1.23".to_f
=> 1.23
irb(main):007:0> "1.23".to_d
=> #<BigDecimal:7ff7dea40b68,'0.123E1',18(18)>
irb(main):008:0> 1.23.to_s
=> "1.23"
irb(main):008:0> 1.23.to_i
=> 1

Логическое приведение является функцией Rails,Вы можете сделать это:

# Rails 5
ActiveModel::Type::Boolean.new.cast(value) 
ActiveModel::Type::Boolean.new.cast("true") # true
ActiveModel::Type::Boolean.new.cast("t") # true 
ActiveModel::Type::Boolean.new.cast("false") # false
ActiveModel::Type::Boolean.new.cast("f") # false
# This is somewhat surprising
ActiveModel::Type::Boolean.new.cast("any arbitrary string") # true


# Rails 4.2
ActiveRecord::Type::Boolean.new.type_cast_from_database(value)

# Rails 4.1 and below
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)

Обратите внимание, что это сильно отличается от логического принуждения Ruby, выполняемого ! и !!.

irb(main):008:0> !!"false"
(irb):8: warning: string literal in condition
=> true

В Ruby все, кроме nilи ложь верны.

Даты несколько сложнее.Входные данные Rails по умолчанию используют мультипараметры для отправки каждой части даты (год, месяц, день) и специальный установщик, который создает дату из этих входных данных.

Processing by PeopleController#create as HTML
  Parameters: { "person"=>{"birthday(1i)"=>"2019", "birthday(2i)"=>"2", "birthday(3i)"=>"16"}, ...}

Вы можете построить дату из этих параметров следующим образом:

date_params = params.fetch(:person).permit("birthday")
Date.new(*date_params.values.map(&:to_i))

Каков наилучший способ приведения данных хеш-значения?

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

Столбцы JSON отлично подходят для решения некоторых сложных проблем, таких как таблицы ключ / значение или для хранения необработанных данных JSON, но они не должны быть вашим первым выбором при моделировании ваших данных.

См. Анти-паттерны PostgreSQL: ненужные динамические столбцы json / hstore для хорошего описания темы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...