Chapter 09

1:多のアソシエーションをつくる

toyoshi
toyoshi
2021.12.30に更新
このチャプターの目次

Articleは複数のCommentを持っているとします。ArticleとCommentに1:多の関係を作ります。

articleのスキーマをにhas_manyを加えます

  schema "articles" do
    field :body, :string
    field :title, :string
    timestamps()

    has_many :comments, Blog.Articles.Comment #書き加える
  end

commentsテーブルを作ります。

% mix ecto.gen.migration create_comments  

内容は次のとおり

defmodule Blog.Repo.Migrations.CreateComments do
  use Ecto.Migration

  def change do
    create table(:comments) do
      add :body, :text
      add :article_id, references(:articles) #これが大事
      timestamps()
    end
  end
end

Commentのスキーマを作りますこちらはbelongs_toで関係を記述します。

defmodule Blog.Articles.Comment do
  use Ecto.Schema
  import Ecto.Changeset

  schema "comments" do
    field :body, :string
    timestamps()

    belongs_to :article, Blog.Articles.Article
  end

  @doc false
  def changeset(comment, attrs) do
    comment
    |> cast(attrs, [:body])
    |> validate_required([:body])
  end
end

マイグレートしたら完成

% mix ecto.migrate

保存する

> article1 = Blog.Articles.get_article!(1)
> comment = Ecto.build_assoc(article1, :comments, %{body: "I like this article."}) 
%Blog.Articles.Comment{
  __meta__: #Ecto.Schema.Metadata<:built, "comments">,
  article: #Ecto.Association.NotLoaded<association :article is not loaded>,
  article_id: 1,
  body: "I like this article.",
  id: nil,
  inserted_at: nil,
  updated_at: nil
}

> Blog.Repo.insert!(comment)
[debug] QUERY OK db=0.4ms idle=1362.8ms
INSERT INTO "comments" ("article_id","body","inserted_at","updated_at") VALUES (?,?,?,?) RETURNING "id" [1, "I like this article.", "2021-12-30T13:41:08", "2021-12-30T13:41:08"]
%Blog.Articles.Comment{
  __meta__: #Ecto.Schema.Metadata<:loaded, "comments">,
  article: #Ecto.Association.NotLoaded<association :article is not loaded>,
  article_id: 1, #Article IDが紐つけられている
  body: "I like this article.",
  id: 1,
  inserted_at: ~N[2021-12-30 13:41:08],
  updated_at: ~N[2021-12-30 13:41:08]
}

参照

preloadが必要

def get_article!(id), do: Repo.get!(Article, id) |> Repo.preload(:comments
<h1>Show Article</h1>

<ul>

  <li>
    <strong>Title:</strong>
    <%= @article.title %>
  </li>

  <li>
    <strong>Body:</strong>
    <%= @article.body %>
  </li>

</ul>

<p>

  <%= for comment <- @article.comments do %>
    <%= comment.body %>
  <%= end %>
</p>