как изменить миграцию рельсов t.timestamps для использования `timestamp (0) без timezone` в postgres - PullRequest
0 голосов
/ 23 октября 2018

Я пытаюсь выяснить, как изменить собственный тип данных, который t.timestamps использует в миграции rails.Тип по умолчанию, который заканчивается в postgres - timestamp without timezone.Вместо этого мне бы хотелось, чтобы timestamp(0) without timezone.

Я хотел бы изменить собственный тип данных, чтобы при создании новой таблицы и использовании t.timestamps в процессе миграции автоматически создавалась правильная временная метка.тип данных.

Мне требуется timestamp(0) without timezone, потому что мое приложение rails разделяет свою БД с приложением laravel, и оба приложения могут вставлять данные.Из-за того, что рельсы используют миллисекунды / laravel нет, и, похоже, не существует способа (по состоянию на 2018-10-23) для laravel поддерживать наличие таблицы, которая содержит разные форматы временных меток (Y-m-d H:i:s.u противY-m-d H:i:s) без необходимости выключать временные метки в модели, по существу отключая автоматическое управление ими, я бы хотел, чтобы база данных принудительно использовала один формат (Y-m-d H:i:s).

Для более подробной информации, пожалуйста, мой другой вопрос: Есть ли способ изменить временные метки по умолчанию в Rails на Ymd H: i: s (вместо Ymd H: i: su) или чтобы laravel игнорировал десятичную частьГмд H: i: su?

Поэтому я хочу использовать timestamp(0) для усечения миллисекунд, и мне не нужно думать о правильной настройке типов меток времени таблиц при создании новой таблицы, как о нативном типебудет уже timestamp(0)

Я пробовал это

./config/environments/initializers

require "active_record/connection_adapters/postgresql_adapter"

module ActiveRecord
 module ConnectionAdapters
   class PostgreSQLAdapter
     NATIVE_DATABASE_TYPES.merge!(
      timestamp: { name: "timestamp(0) without timezone" }
     )
   end
 end
end

и миграцию, как

class ChangeTimestampTypesToTimestamp0 < ActiveRecord::Migration[5.2]
  def change
    create_table :test, id: :uuid, default: -> { "gen_random_uuid()" } do|t|
      t.string :name, null: false

      t.timestamps
    end
  end
end

, но это не сработало.

Я также пытался изменить метку времени, чтобы использовать метку времени с той же миграцией, что и выше, в качестве проверки работоспособности, но все же не повезло ...

require "active_record/connection_adapters/postgresql_adapter"

module ActiveRecord
 module ConnectionAdapters
   class PostgreSQLAdapter
     NATIVE_DATABASE_TYPES.merge!(
       timestamp: { name: "timestamptz" }
     )
   end
 end
end

enter image description here

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Вот решение.Он изменяет точность меток времени по умолчанию в Rails, в том числе для миграции, для двух меток времени с точностью до одной секунды в PostgreSQL.Это не просто и не просто, но работает для Rails 5.2 с PostgreSQL.

Я думаю, инициализатор должен быть помещен в config/initializers/ (не в environments).
Напишите следующий файл.

# ./config/initializers/arbitrary.rb

require "active_record/connection_adapters/abstract/schema_definitions.rb"
require "active_record/connection_adapters/abstract_adapter"
require "active_record/connection_adapters/abstract/schema_statements"
require "active_record/connection_adapters/postgresql/schema_statements"
require "active_record/connection_adapters/postgresql_adapter"

module ActiveRecord
  module ConnectionAdapters
    # Overwrites a method in /abstract/schema_definitions.rb
    class TableDefinition
      def timestamps(**options)
        options[:null] = false if options[:null].nil?

        column(:created_at, :datetime0, options)
        column(:updated_at, :datetime0, options)
      end
    end

    # Overwrites a method in /abstract/schema_statements.rb
    module SchemaStatements
      def add_timestamps(table_name, options = {})
        options[:null] = false if options[:null].nil?

        add_column table_name, :created_at, :datetime0, options
        add_column table_name, :updated_at, :datetime0, options
      end
    end

    # Overwrites a method in /postgresql/schema_statements.rb
    module PostgreSQL
      module SchemaStatements
        def add_timestamps_for_alter(table_name, options = {})
          [add_column_for_alter(table_name, :created_at, :datetime0, options), add_column_for_alter(table_name, :updated_at, :datetime0, options)]
        end
      end
    end

    # Modifies a constant and methods in /postgresql_adapter.rb
    class PostgreSQLAdapter
      alias_method :initialize_type_map_orig, :initialize_type_map if ! self.method_defined?(:initialize_type_map_orig)
      NATIVE_DATABASE_TYPES[:datetime0] = { name: "timestamp(0)" }

      private    
        def initialize_type_map(m = type_map)
          register_class_with_precision_t0 m, "timestamp0", OID::DateTime
          initialize_type_map_orig(m)
        end

        def register_class_with_precision_t0(mapping, key, klass)
          mapping.register_type(key) do |*args|
            klass.new(precision: 0)
          end
        end
    end
  end
end

Вот пример файла миграции.

# db/migrate/20181023182238_create_articles.rb
class CreateArticles < ActiveRecord::Migration[5.2]
  def change
    create_table :articles do |t|
      t.string :title
      t.timestamps
    end
  end
end

Миграция (bin/rails db:migrate) создает таблицу articles с двумя столбцами меток времени timestamp(0) (без часового пояса) в PostgreSQLбаза данных.

Выполнено SQL:

CREATE TABLE "articles" (
  "id" bigserial primary key, 
  "title" character varying, 
  "created_at" timestamp(0) NOT NULL,
  "updated_at" timestamp(0) NOT NULL);

Примечание

Я подтвердил как миграцию для создания таблицы, так и работы по обновлению данных в консоли Raisl.Он также предназначен для совместной работы по обновлению таблицы, но я не проверял его.

При более тонкой настройке он будет работать и в других базах данных.

В основномКод выше определяет новый тип Rails timestamp0, которому назначен timestamps() (то есть created_at и updated_at).Если вы хотите, чтобы любые другие столбцы метки времени были одинаковыми (т. Е. С точностью до секунды в БД), укажите timestamp0 в своей миграции, и она должна работать (хотя я не проверял).

0 голосов
/ 24 октября 2018

Полагаю, я понял это!

Я начал изучать то, что NATIVE_DATABASE_TYPES принесли, установив переменную из консоли

Rails c
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES

Результат: {:primary_key=>"bigserial primary key", :string=>{:name=>"character varying"}, :text=>{:name=>"text"}, :integer=>{:name=>"integer", :limit=>4}, :float=>{:name=>"float"}, :decimal=>{:name=>"decimal"}, :datetime=>{:name=>"timestamp"}, :time=>{:name=>"time"}, :date=>{:name=>"date"}, :daterange=>{:name=>"daterange"}, :numrange=>{:name=>"numrange"}, :tsrange=>{:name=>"tsrange"}, :tstzrange=>{:name=>"tstzrange"}, :int4range=>{:name=>"int4range"}, :int8range=>{:name=>"int8range"}, :binary=>{:name=>"bytea"}, :boolean=>{:name=>"boolean"}, :xml=>{:name=>"xml"}, :tsvector=>{:name=>"tsvector"}, :hstore=>{:name=>"hstore"}, :inet=>{:name=>"inet"}, :cidr=>{:name=>"cidr"}, :macaddr=>{:name=>"macaddr"}, :uuid=>{:name=>"uuid"}, :json=>{:name=>"json"}, :jsonb=>{:name=>"jsonb"}, :ltree=>{:name=>"ltree"}, :citext=>{:name=>"citext"}, :point=>{:name=>"point"}, :line=>{:name=>"line"}, :lseg=>{:name=>"lseg"}, :box=>{:name=>"box"}, :path=>{:name=>"path"}, :polygon=>{:name=>"polygon"}, :circle=>{:name=>"circle"}, :bit=>{:name=>"bit"}, :bit_varying=>{:name=>"bit varying"}, :money=>{:name=>"money"}, :interval=>{:name=>"interval"}, :oid=>{:name=>"oid"}

выясняется, что timestamp фактически никогда не устанавливалось до того, как я начал включать его с моим

module ActiveRecord
 module ConnectionAdapters
   class PostgreSQLAdapter
     NATIVE_DATABASE_TYPES.merge!(
      timestamp: { name: "timestamp", limit:0 }
     )
   end
 end
end

То, что включалось, считалось datetime, и я понял, что timestamp был псевдонимомиз datetime.

Я изменил слияние NATIVE_DATABASE_TYPES, чтобы оно выглядело следующим образом ...

require "active_record/connection_adapters/postgresql_adapter"

module ActiveRecord
 module ConnectionAdapters
   class PostgreSQLAdapter
     NATIVE_DATABASE_TYPES.merge!(
       datetime: { name: "timestamp", limit:0 }
     )
   end
 end
end

Я запустил миграцию, и столбцы были успешно установлены на timestamp(0) without timezone

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