LoginSignup
5
2

More than 1 year has passed since last update.

Active Record(Ruby)とEcto(Elixir)でmigrateした内容を一致させる

Last updated at Posted at 2021-07-17

はじめに

  • Elixir楽しんでいますか:bangbang::bangbang::bangbang:
  • Active Record(Ruby)でmigrateした内容とぴったり同じものをEcto(Elixir)でマイグレーションファイルを書きたいということがありました
  • データベースはPostgreSQLを使いました
  • ググってみてもなかなか答えは見つかりませんでした
  • 特定のActive Record(Ruby)のマイグレーションファイルを正解(期待)として、なんとなくカンでEcto(Elixir)のマイグレーションファイルを書いてみたら一致したのでそのことを記事に残しておきます
  • 使用したライブラリなどのバージョンは以下の通りです
バージョン バージョン確認コマンド
PostgreSQL 13.2 psql --version
Ruby 2.6.2 ruby -v
Active Record 5.2.4.1 cat Gemfile.lock
Elixir 1.9.4 elixir -v
Ecto 3.3.4 cat mix.lock

Active Record(Ruby)のマイグレーションファイル

# frozen_string_literal: true

class DeviseCreateAdminUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :admin_users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # t.integer  :sign_in_count, default: 0, null: false
      # t.datetime :current_sign_in_at
      # t.datetime :last_sign_in_at
      # t.inet     :current_sign_in_ip
      # t.inet     :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :admin_users, :email,                unique: true
    add_index :admin_users, :reset_password_token, unique: true
    # add_index :admin_users, :confirmation_token,   unique: true
    # add_index :admin_users, :unlock_token,         unique: true
  end
end
$ psql -U postgres

postgres=# \c workflows_repo

workflows_repo=# \d admin_users
                                              Table "public.admin_users"
         Column         |            Type             | Collation | Nullable |                 Default                 
------------------------+-----------------------------+-----------+----------+-----------------------------------------
 id                     | bigint                      |           | not null | nextval('admin_users_id_seq'::regclass)
 email                  | character varying           |           | not null | ''::character varying
 encrypted_password     | character varying           |           | not null | ''::character varying
 reset_password_token   | character varying           |           |          | 
 reset_password_sent_at | timestamp without time zone |           |          | 
 remember_created_at    | timestamp without time zone |           |          | 
 created_at             | timestamp without time zone |           | not null | 
 updated_at             | timestamp without time zone |           | not null | 
Indexes:
    "admin_users_pkey" PRIMARY KEY, btree (id)
    "index_admin_users_on_email" UNIQUE, btree (email)
    "index_admin_users_on_reset_password_token" UNIQUE, btree (reset_password_token) 

Ecto(Elixir)マイグレーションファイル

  • ぴったり一致するEctoのマイグレーションファイルは以下のようになります
defmodule Workflows.Repo.Migrations.CreateAdminUsers do
  use Ecto.Migration

  def change do
    create table(:admin_users) do
      add :email, :"character varying", default: "", null: false
      add :encrypted_password, :"character varying", default: "", null: false
      add :reset_password_token, :"character varying", size: nil
      add :reset_password_sent_at, :"timestamp without time zone"
      add :remember_created_at, :"timestamp without time zone"

      add :created_at, :"timestamp without time zone", null: false
      add :updated_at, :"timestamp without time zone", null: false
    end

    create unique_index(:admin_users, [:email], name: :index_admin_users_on_email)
    create unique_index(:admin_users, [:reset_password_token], name: :index_admin_users_on_reset_password_token)
  end
end
  • Typeを指定するところに、psqlで確認した:"character varying":"timestamp without time zone"とカンで書いてみるとぴったり一致しました
  • インデックスの名前は、:nameで指定しました

一致しないマイグレーションファイル

defmodule Workflows.Repo.Migrations.CreateAdminUsers do
  use Ecto.Migration

  def change do
    create table(:admin_users) do
      add :email, :string, default: "", null: false
      add :encrypted_password, :string, default: "", null: false
      add :reset_password_token, :string, size: nil
      add :reset_password_sent_at, :utc_datetime
      add :remember_created_at, :utc_datetime

      add :created_at, :utc_datetime, null: false
      add :updated_at, :utc_datetime, null: false
    end

    create unique_index(:admin_users, [:email])
    create unique_index(:admin_users, [:reset_password_token])
  end
end
  • Typeを:string:utc_datetimeにしてmix ecto.migrateすると以下のように少し異なったものがつくられます
  • インデックスの名前は、:nameオプションを指定しない場合、少し異なっています
                                                Table "public.admin_users"
         Column         |              Type              | Collation | Nullable |                 Default                 
------------------------+--------------------------------+-----------+----------+-----------------------------------------
 id                     | bigint                         |           | not null | nextval('admin_users_id_seq'::regclass)
 email                  | character varying(255)         |           | not null | ''::character varying
 encrypted_password     | character varying(255)         |           | not null | ''::character varying
 reset_password_token   | character varying(255)         |           |          | 
 reset_password_sent_at | timestamp(0) without time zone |           |          | 
 remember_created_at    | timestamp(0) without time zone |           |          | 
 created_at             | timestamp(0) without time zone |           | not null | 
 updated_at             | timestamp(0) without time zone |           | not null | 
Indexes:
    "admin_users_pkey" PRIMARY KEY, btree (id)
    "admin_users_email_index" UNIQUE, btree (email)
    "admin_users_reset_password_token_index" UNIQUE, btree (reset_password_token)

Wrapping up :lgtm::lgtm::lgtm::lgtm:

  • この記事を書く前は、どこにも書いてなかったので記事にしました〜 というつもりで書いていました
  • https://hexdocs.pm/ecto_sql/Ecto.Migration.html#module-field-types をよく見ると、この記事で紹介したようなTypeの指定方法が書いてありました :sweat_smile:
  • どなたかのお役に立てることがあるかもしれませんので記事を残しておきます
    • character varying no limit postgres ectoとかで検索しましたがなかなかヒットしなかったので:sweat_smile:
  • まとめとしては、以下の手順でやればよいです
    • 正解(期待)スキーマを確認する
    • EctoのマイグレーションファイルでTypeはスキーマに書いてある型をAtomで指定する
  • Enjoy Elixir:bangbang::bangbang::bangbang:
  • この記事は、2021/07/17(土) 00:00 〜 2021/07/19(月) 23:59開催のautoracex #37という純粋なもくもく会での成果です
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2