[Elixir][Phoenix]has_oneやbelongs_toの関係にあるモデルを、他方のモデル生成時に合わせて生成する

has_onebelongs_to の関係になっているDeviceとUserのモデルを考えた時に、Device作成時にUserモデルも新規に作成したい時の話。

このメソッドは対象は、Phoenixのcreateリクエストを元にしています。
Rep.transaction とその中で依存性を持つ複数のDB処理を一括で書いています。

has_onebelongs_to の関係を持っているので、一方の _id に、もう一方の id を与える必要がある、ところがポイント。

もっとちゃんとした書き方あるのかな。ありそうな気がする。。。

  def create(conn, %{"device" => device_params}) do
    changeset = Device.changeset(%Device{}, device_params)

    if changeset.valid? do
      # 以下、追加しているところ
      Repo.transaction(fn->
        # deviceをまず作成
        device = Repo.insert!(changeset)
        # device.idとして belongs_to の関係を持つ User を作成
        user = Repo.insert! %User{device_id: device.id, user_name: "your name", user_sex: "male"}
        # has_oneの関係をdeviceは持つので、userとして直前で生成した
        # userを与える
        device = Repo.update! %Device{device | user: user}
      end)

      conn
      |> put_flash(:info, "Device created successfully.")
      |> redirect(to: device_path(conn, :index))
    else
      render(conn, "new.html", changeset: changeset)
    end
  end

この関係が正しくできているかは、controllerレベルでは以下のように適当なユーザを生成して、その上でindexなどが表示できることを確認すればOK。
この時、index.htmlでは device.user.user_name のような、has_oneの関係にある要素を描画しようとしていることが必要ですが。

  test "lists all entries on index after create items.", %{conn: conn} do
    post conn, device_path(conn, :create), device: @valid_attrs
    conn = get conn, device_path(conn, :index)
    assert html_response(conn, 200) =~ "Listing devices"
  end

Railsに似ているので、Railsも参考にしながら書いてみているけれど、DB周りの扱いがだいぶ想像できるようになってきた感じ。

まだ公開していないけれど、練習用repositoryはこちら

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中