スポンサーリンク

2015年7月1日

[Phoenix]Ectoで1対多の関係性を検証する

目的

Ectoで1対多の関係性を検証する。

実行環境

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. 1対多の関係?
  2. has_manyを検証!

1. 1対多の関係?

1対多の関係と言うと何が思いつくでしょうか?
男一人に対して女複数人のハーレム。(またはその逆)
若しくは、複数人に対しての浮気。
碌なのが思いつかないですね。(冗談)
閑話休題。
簡単なWebサイトを例にしましょう。
登録しているユーザが記事を投稿できるWebサイトがあります。
その場合、ユーザ一人に対して複数の記事が紐づけられますね。
そういった場合に今回実施する1対多の関係性を設定しておくと楽になるわけです。
(一々、SQL文で探して結合してなんてやりたくないです・・・)
Ectoには以下のような機能があります。
  • Schema.has_many/3
  • Schema.belongs_to/3
  • Schema.has_one/3
大体どれを使うか想像ができたのではないでしょうか?

2. has_manyを検証!

では、実際に検証していきましょう。
まず、Userモデル以外に新しいモデルを作成します。
記事モデルでいいか・・・
データモデルは以下になります。
microposts: id:integer, content:string, user_id:integer, timestamp
※idとtimestampは自動で作成されるので、それ以外の項目を指定する
>mix phoenix.gen.html Micropost microposts content:string user_id:integer
DBでSQLを使ってデータを入れるのが面倒くさいので、
画面上からmicropostsテーブルへデータを入力するために”gen.html”を使用している。
>mix ecto.migrate
[info] == Running EctoModelsSample.Repo.Migrations.CreateMicropost.change/0 forward
[info] create table microposts
[info] == Migrated in 0.2s
それでは、二つのモデルを編集します。
web/models/user.exを開き、
スキーマを以下のように編集して下さい。
schema "users" do
  field :name, :string
  field :email, :string

  has_many :microposts, EctoModelsSample.Micropost
  timestamps
end
web/models/micropost.exを開き、
スキーマを以下のように編集して下さい。
schema "microposts" do
  field :content, :string
  belongs_to :user, EctoModelsSample.User, foreign_key: :user_id

  timestamps
end

@required_fields ~w(content user_id)
@optional_fields ~w()
Tips:
foreign_keyを指定しない場合、
“:user+_id = user_id”と言った形で補完するようです。
次にUserコントローラを修正します。
web/controllers/user_contoroller.exを開き、
以下のように関数を編集して下さい。
def index(conn, _params) do
  users = EctoModelsSample.User |> Repo.all() |> Repo.preload [:microposts]
  render(conn, "index.html", users: users)
end
def show(conn, %{"id" => id}) do
  user = EctoModelsSample.User |> Repo.get(id) |> Repo.preload [:microposts]
  render(conn, "show.html", user: user)
end
Micropostを画面上に表示させたいですね!
テンプレートに以下のようなコードを記述すれば表示できます。
<%= for user <- @users do %>
  <%= user.name %>
  <%= user.email %>

  <%= for post <- user.microposts do %>
    <%= post.content %>
  <% end %>
<% end %>

管理人の独り言~

Phoenixのガイドだとuser_idを生成していないのだが・・・
どうやってあれで動いているのだろうか・・・
検証として、user_idを生成しないパターンも行ったのですが、
そうすると実行時に「user_idなんてキーねぇよ」って怒られるのです。
まだ不明な所は残っているが、
1対多の関係性を検証できたからとりあえず良しとしよう。
また後でhexdocs - Ecto.Schemaを参考にしてやってみよう。

参考文献

人気の投稿