Do you want to pick up from where you left of?
Take me there

基本

Ectoはデータベースラッパーと統合クエリ言語を提供するElixirの公式なプロジェクトです。Ectoによりマイグレーション、スキーマの定義、レコードの挿入や更新、そしてそれらに対するクエリが可能になります。

アダプタ

Ectoアダプタを使用することで異なるデータベースをサポートします。アダプタの例として以下のものがあります:

このレッスンではPostgreSQLアダプタを使用するようにEctoを設定します。

はじめに

このレッスンのコースを通して、私たちはEctoの3つの機能を学びます:

まずはスーパーバイザーツリーを持つアプリケーションを作ります。

mix new friends --sup
cd friends

mix.exs ファイルにectoとpostgrexパッケージの依存を追加します。

  defp deps do
    [
      {:ecto_sql, "~> 3.2"},
      {:postgrex, "~> 0.15"}
    ]
  end

次のコマンドで依存を取得します。

mix deps.get

レポジトリの作成

EctoのレポジトリはPostgresデータベースのようなデータストアをマップします。 データベースとの全ての通信はこのレポジトリを使用して行われます。

次のコマンドを実行してレポジトリをセットアップしましょう:

mix ecto.gen.repo -r Friends.Repo

これは、使用するアダプタを含むデータベースとの接続にの中に必要な設定を config/config.exs の中に生成します。 これが Friends アプリケーションのための設定ファイルとなります。

config :friends, Friends.Repo,
  database: "friends_repo",
  username: "postgres",
  password: "",
  hostname: "localhost"

これはEctoがどのようにデータベースと接続するかを構成します。

またこれは lib/friends/repo.ex の中に Friends.Repo を作ります。

defmodule Friends.Repo do
  use Ecto.Repo, 
    otp_app: :friends,
    adapter: Ecto.Adapters.Postgres
end

データベースにクエリを発行するには Friends.Repo を使います。また、このモジュールに対してElixirアプリ :friends 内のデータベース接続情報を見つけるように指示を出し、adapterは Ecto.Adapters.Postgres を選択します。

次に、 lib/friends/application.ex の中で Friends.Repo をアプリケーションのスーパーバイザーツリーにおけるスーパーバイザーとして設定します。
これによって、アプリケーション開始時にEctoプロセスを開始します。

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      Friends.Repo,
    ]

  ...

その後、 config/config.exs ファイルに次の行を追加する必要があります:

config :friends, ecto_repos: [Friends.Repo]

これにより、アプリケーションがコマンドラインからEctoのmixコマンドを実行できるようになります。

レポジトリの設定は全て終わりました! 次のコマンドでPostgresの中にデータベースを作ることができます:

mix ecto.create

Ectoは config/config.exs ファイルの中の情報を使って、Postgresへの接続方法、そしてデータベースに与える名前を決定します。

もし何らかのエラーがあれば、接続情報が正しいこと、Postgresのインスタンスが実行されていることを確認してください。

マイグレーション

Postgresデータベース内のテーブルの作成と更新をするために、Ectoはマイグレーションを提供しています。 それぞれのマイグレーションは、どのテーブルが作成されたり更新されるのかというような、データベースで実行されるアクションの集合を定義します。

私たちのデータベースはまだテーブルを持っていないので、何かを追加するマイグレーションを作る必要があります。 Ectoの慣習ではテーブルを複数形にすることから、私たちのアプリケーションでは people テーブルが必要なので、そこからマイグレーションを始めましょう。

マイグレーションを作るベストな方法は、mixの ecto.gen.migration <name> タスクなので、私たちの場合は次のように使いましょう:

mix ecto.gen.migration create_people

これは priv/repo/migrations フォルダの中にタイムスタンプを名前に含んだ新しいファイルを生成します。 ディレクトリに移動してマイグレーションを開くと、次のようなものが確認できるはずです:

defmodule Friends.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do

  end
end

nameage を持った people テーブルを新たに作るために、 change/0 関数を修正することから始めましょう:

defmodule Friends.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do
    create table(:people) do
      add :name, :string, null: false
      add :age, :integer, default: 0
    end
  end
end

上のコードではカラムのデータの型も定義していることが確認できるでしょう。 さらに、 null: falsedefault: 0 をオプションとして加えました。

シェルに移動してマイグレーションを実行してみましょう:

mix ecto.migrate

スキーマ

最初のテーブルを作成したところで、スキーマを通してどうするのかについて、Ectoにさらに詳細を伝える必要があります。 スキーマは、データベーステーブルのフィールドをマップするモジュールです。

Ectoはデータベーステーブルの名前を複数形とするのに対して、スキーマは通常単数形であるため、テーブルに合わせて Person というスキーマを作ります。

それでは新しいスキーマを lib/friends/person.ex に作ってみましょう。

defmodule Friends.Person do
  use Ecto.Schema

  schema "people" do
    field :name, :string
    field :age, :integer, default: 0
  end
end

この Friends.Person は、それが people テーブルと関連するものであることをEctoに伝え、stringの name とintegerでデフォルトが0の age という2つのカラムを持っていることがわかります。

iex -S mix を開いて新しい人を作ることで、このスキーマを覗いてみましょう:

iex> %Friends.Person{}
%Friends.Person{age: 0, name: nil}

期待通りデフォルト値が適用された age を持つ Person ができました。 それでは”本当の”人を作ってみましょう:

iex> person = %Friends.Person{name: "Tom", age: 11}
%Friends.Person{age: 11, name: "Tom"}

スキーマはただの構造体なので、これまでのようにデータを扱うことができます:

iex> person.name
"Tom"
iex> Map.get(person, :name)
"Tom"
iex> %{name: name} = person
%Friends.Person{age: 11, name: "Tom"}
iex> name
"Tom"

同じように、Elixirの他のマップや構造体に対して行ったようにスキーマを更新できます:

iex> %{person | age: 18}
%Friends.Person{age: 18, name: "Tom"}
iex> Map.put(person, :name, "Jerry")
%Friends.Person{age: 11, name: "Jerry"}

次のチェンジセットのレッスンでは、データの変更をバリデーションする方法と、最終的にそれらをデータベースに永続化する方法について見ていきます。

間違いを報告したい、あるいはこのレッスンに貢献したい? このレッスンをGitHubで編集しよう!