スポンサーリンク

2015年6月30日

[Phoenix]Ectoを使って再マイグレーションする

目的

Ectoで再マイグレーションを行う。

実行環境

OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Phoenix Framework: v0.13.1
PostgreSQL: postgres (PostgreSQL) 9.4.4

始める前に

おそらく必要となると思うので先行して書いておく。
先日の記事を元に実施しますので、
プロジェクトの作成とマイグレーションは終わらせておいて下さい。
よければ参考に・・・
[Elixir+Phoenix]EctoModelsの機能を使う
準備良し。
以降、この記事でのプロジェクトと言えば、
“ecto_models_sample”を指し示す。

目次

  1. マイグレーション再び
  2. カラム追加
  3. カラム削除

1. マイグレーション再び

再マイグレーションの検証を行う。
マイグレーションして生成したテーブルにカラムの追加/削除を行う。
まぁ、データモデルやDB設計の段階でしっかりしろよ!
と言われるかもしれないが、往々にして起こり得ることだと思う。
なので、Ectoで再マイグレーションする方法を書いておく。
カラムの追加/削除だけですが・・・おつきあいくだせー。
今回は、usersテーブルに対してageの項目を追加/削除してみる。

2. カラム追加

さて、ではカラムの追加をしていきます。
まずはマイグレーションファイルを作成します。
マイグレーションする際の名前は重要。
一目で分かるような名前にしておく。
>mix ecto.gen.migration add_age_to_users
* creating priv/repo/migrations
* creating priv/repo/migrations/20150630005902_add_age_to_users.exs
priv/repo/migrationsディレクトリへ行き、
20150630005902_add_age_to_users.exsを開いて下さい。
内容を以下のように編集して下さい。
defmodule EctoModelsSample.Repo.Migrations.AddAgeToUsers do
  use Ecto.Migration

  def change do
    alter table(:users) do
      add :age, :integer
    end
  end
end
マイグレーションしてみます。
>mix ecto.migrate
[info] == Running EctoModelsSample.Repo.Migrations.AddAgeToUsers.change/0 forward
[info] alter table users
[info] == Migrated in 0.0s
動作にエラーは出てない。
問題ないですね。
Tips
再マイグレーションした場合、どのソースに変更を加えればいいのでしょうか?
今回のプロジェクトには、”mix phoenix.gen.html”で生成されたソースコードがあります。
こちらを例に説明します。
まずはモデルモジュールを変更しなくてはなりません。
スキーマへと@required_fieldsへカラムを追加しています。
web/models/user.ex
defmodule EctoModelsSample.User do
  ...
  schema "users" do
    field :name, :string
    field :email, :string
    field :age, :integer

    timestamps
  end

  @required_fields ~w(name email age)
  @optional_fields ~w()
  ...
end
テンプレートを変更しないと表示されませんね。
(やらなくてもエラーは出なかったですけど・・・)
対象としたのは以下のテンプレートです。
web/templates/user/index.html.eex
web/templates/user/show.html.eex
web/templates/user/form.html.eex
一応ソースコードを載せますが・・・参考になることはないと思います。(所詮コピペ)
皆さんが表示したいように実施して下さい。
index.html.eex
<h2>Listing users</h2>

<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Age</th>

      <th></th>
    </tr>
  </thead>
  <tbody>
<%= for user <- @users do %>
    <tr>
      <td><%= user.name %></td>
      <td><%= user.email %></td>
      <td><%= user.age %></td>

      <td class="text-right">
        <%= link "Show", to: user_path(@conn, :show, user), class: "btn btn-default btn-xs" %>
        <%= link "Edit", to: user_path(@conn, :edit, user), class: "btn btn-default btn-xs" %>
        <%= link "Delete", to: user_path(@conn, :delete, user), method: :delete, class: "btn btn-danger btn-xs" %>
      </td>
    </tr>
<% end %>
  </tbody>
</table>

<%= link "New user", to: user_path(@conn, :new) %>
show.html.eex
<h2>Listing users</h2>

<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Age</th>

      <th></th>
    </tr>
  </thead>
  <tbody>
    <%= for user <- @users do %>
    <tr>
      <td><%= user.name %></td>
      <td><%= user.email %></td>
      <td><%= user.age %></td>

      <td class="text-right">
        <%= link "Show", to: user_path(@conn, :show, user), class: "btn btn-default btn-xs" %>
        <%= link "Edit", to: user_path(@conn, :edit, user), class: "btn btn-default btn-xs" %>
        <%= link "Delete", to: user_path(@conn, :delete, user), method: :delete, class: "btn btn-danger btn-xs" %>
      </td>
    </tr>
<% end %>
  </tbody>
</table>

<%= link "New user", to: user_path(@conn, :new) %>
form.html.eex
<%= form_for @changeset, @action, fn f -> %>
  <%= if f.errors != [] do %>
    <div class="alert alert-danger">
      <p>Oops, something went wrong! Please check the errors below:</p>
      <ul>
        <%= for {attr, message} <- f.errors do %>
          <li><%= humanize(attr) %> <%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-group">
    <label>Name</label>
    <%= text_input f, :name, class: "form-control" %>
  </div>

  <div class="form-group">
    <label>Email</label>
    <%= text_input f, :email, class: "form-control" %>
  </div>

  <div class="form-group">
    <label>Age</label>
    <%= text_input f, :age, class: "form-control" %>
  </div>

  <div class="form-group">
    <%= submit "Submit", class: "btn btn-primary" %>
  </div>
<% end %>

3. カラム削除

ではでは、ageカラムを削除します。
>mix ecto.gen.migration remove_age_to_users
* creating priv/repo/migrations
* creating priv/repo/migrations/20150630014132_remove_age_to_users.exs
作成されたファイルを以下のように編集します。
defmodule EctoModelsSample.Repo.Migrations.RemoveAgeToUsers do
  use Ecto.Migration

  def change do
    alter table(:users) do
      remove :age
    end
  end
end
マイグレーションします。
>mix ecto.migrate
[info] == Running EctoModelsSample.Repo.Migrations.RemoveAgeToUsers.change/0 forward
[info] alter table users
[info] == Migrated in 0.0s
これで削除完了です。

管理人の独り言~

今回はすんなり終わった。
毎回こうだと楽でいいのだが・・・
最近、リモートワークのルールを学習プロセスに取り入れてみようと思った。
ルールができたら、また駄文の記事を作成しようと思う。

参考文献

人気の投稿