凤凰应用程序中的多个belongs_to

时间:2016-10-15 16:53:07

标签: elixir phoenix-framework

以下是我目前拥有的三种型号

routine.ex

defmodule DailyRoutine.Routine do
  use DailyRoutine.Web, :model

  schema "routines" do
    field :title, :string
    field :timeframe, :integer
    field :content, :string
    belongs_to :user, DailyRoutine.User
    has_many :comments, DailyRoutine.Comment 

    timestamps
  end

  @required_fields ~w(title timeframe content)
  @optional_fields ~w()
  # rest of the code goes here
end

user.ex

defmodule DailyRoutine.User do
  use DailyRoutine.Web, :model

  schema "users" do
    field :name, :string
    field :username, :string
    field :password, :string, virtual: true
    field :password_hash, :string
    has_many :routines, DailyRoutine.Routine
    has_many :comments, DailyRoutine.Comment 

    timestamps
  end

  @required_fields ~w(name username)
  @optional_fields ~w()
  # rest of the model code goes here    
end

comment.ex

defmodule DailyRoutine.Comment do
  use DailyRoutine.Web, :model

  schema "routines" do
    field :content, :string
    belongs_to :user, DailyRoutine.User
    belongs_to :routine, DailyRoutine.Routine

    timestamps
  end

  @required_fields ~w(user_id routine_id content)
  @optional_fields ~w()
  #rest of the code goes here
end

现在问题是我无法在控制器中找到一种方法来执行多个build_assoc并将它们链接在一起以构建适当的变更集。

这是我的控制器:

comment_controller.ex

defmodule DailyRoutine.CommentController do
  use DailyRoutine.Web, :controller
  alias DailyRoutine.Comment

  def create(conn, %{"routine_id" => routine_id, "comment" => comment_params}, user) do
    routine = Repo.get!(DailyRoutine.Routine, routine_id) |> Repo.preload(:user)

    changeset = 
      user
      |> build_assoc(:comments)
      |> Repo.preload(:routine)
      |> Comment.changeset(comment_params)
      |> Ecto.Changeset.put_assoc(:routine, routine)

    case Repo.insert(changeset) do
      {:ok, comment} ->
        conn
        |> put_flash(:info, "Your comment was successfully posted!")
        |> redirect(to: routine_path(conn, :show, routine_id))
      {:error, changeset} ->
        redirect(conn, to: routine_path(conn, :show, routine_id))
    end
  end

  def action(conn, _) do
    apply(__MODULE__, action_name(conn), [conn, conn.params, conn.assigns.current_user])
  end
end

到目前为止我所做的并不起作用,我尝试了多种方法,包括使用特定关系id等手动构建结构。

非常感谢!

1 个答案:

答案 0 :(得分:3)

I would simply put the ids in manually in the struct and pass that to Comment.changeset/2 for this instead of trying to use build_assoc since you already have routine and its user loaded:

changeset =
  %Comment{user_id: user.id, routine_id: routine_id}
  |> Comment.changeset(comment_params)
case Repo.insert(changeset) do
  ...
end

Since you have routine_id and user_id in the @required_fields, you can also put these ids in the params you pass to Comment.changeset/2:

comment_params =
  comment_params
  |> Map.put("user_id", user.id)
  |> Map.put("routine_id", routine_id)
changeset = Comment.changeset(%Comment{}, comment_params)