Phoenixフレームワークで関連付けとネストされたフォームを処理する方法は何ですか? ネストされた属性を持つフォームを作成するにはどうすればよいでしょうか? コントローラーとモデルでそれをどのように処理しますか?
質問する
7999 次
2 に答える
17
1 対 1 の状況を処理する簡単な例があります。
とモデルがあり、明らかにhas_oneがあるCar
と想像してください。車のモデルのコードがありますEngine
Car
Engine
defmodule MyApp.Car do
use MyApp.Web, :model
schema "cars" do
field :name, :string
has_one :engine, MyApp.Engine
timestamps
end
def changeset(model, params \\ :empty) do
model
|> cast(params, ~w(name), ~w())
|> validate_length(:name, min: 5, message: "No way it's that short")
end
end
そしてエンジンモデル
defmodule MyApp.Engine do
use MyApp.Web, :model
schema "engines" do
field :type, :string
belongs_to :car, MyApp.Car
timestamps
end
def changeset(model, params \\ :empty) do
model
|> cast(params, ~w(type), ~w())
|> validate_length(:type, max: 10, message: "No way it's that long")
end
end
フォームのシンプルなテンプレート ->
<%= form_for @changeset, cars_path(@conn, :create), fn c -> %>
<%= text_input c, :name %>
<%= inputs_for c, :engine, fn e -> %>
<%= text_input e, :type %>
<% end %>
<button name="button" type="submit">Create</button>
<% end %>
そしてコントローラー - >
defmodule MyApp.CarController do
use MyApp.Web, :controller
alias MyApp.Car
alias MyApp.Engine
plug :scrub_params, "car" when action in [:create]
def new(conn, _params) do
changeset = Car.changeset(%Car{engine: %Engine{}})
render conn, "new.html", changeset: changeset
end
def create(conn, %{"car" => car_params}) do
engine_changeset = Engine.changeset(%Engine{}, car_params["engine"])
car_changeset = Car.changeset(%Car{engine: engine_changeset}, car_params)
if car_changeset.valid? do
Repo.transaction fn ->
car = Repo.insert!(car_changeset)
engine = Ecto.Model.build(car, :engine)
Repo.insert!(engine)
end
redirect conn, to: main_page_path(conn, :index)
else
render conn, "new.html", changeset: car_changeset
end
end
end
また、いくつかのことを明確にすることができる主題に関する興味深いブログ投稿->ここ
于 2015-08-17T15:48:15.033 に答える
3
関係で同じ問題に遭遇しましたhas_many
。残念ながら、 aCar
は many を持つことができないので、このブログ投稿Engines
で同じ例を取り上げます, of a , with manyTodoList
TodoItems
TodoList
モデル:
defmodule MyApp.TodoList do
use MyApp.Web, :model
schema "todo_lists" do
field :title, :string
has_many :todo_items, MyApp.TodoItem
timestamps
end
def changeset(model, params \\ :{}) do
model
|> cast(params, [:title])
|> cast_assoc(:todo_items)
end
end
TodoItem
モデル:
defmodule MyApp.TodoItem do
use MyApp.Web, :model
schema "todo_items" do
field :body, :string
belongs_to :todo_list, MyApp.TodoList
timestamps
end
def changeset(model, params \\ :{}) do
model
|> cast(params, [:body])
end
end
フォームの作成は次のとおりTodoList
です。簡単にするために、ここでは 1 つの項目を追加します。
<%= form_for @changeset, todo_lists_path(@conn, :create), fn f -> %>
<%= text_input f, :title %>
<%= inputs_for f, :todo_items, fn i -> %>
<%= text_input i, :body %>
<% end %>
<button name="button" type="submit">Create</button>
<% end %>
これはどのようTodoListController
に見えるかです。このcreate
方法は、正しく理解するのが最も難しいものでした。これを機能させる方法を見つけるために、Ecto Tests を掘り下げる必要がありました。リンク
defmodule MyApp.TodoListController do
use MyApp.Web, :controller
alias MyApp.TodoList
alias MyApp.TodoItem
def new(conn, _params) do
todo_item = TodoItem.changeset(%TodoItem{})
changeset = TodoList.changeset(%TodoList{todo_items: [todo_item]})
render conn, "new.html", changeset: changeset
end
def create(conn, %{"todo_list" => todo_list_params}) do
todo_item_changeset =
TodoItem.changeset(%TodoItem{}, todo_item["todo_items"]["0"])
changeset =
TodoList.changeset(%TodoList{}, %{title: todo_list_params["title"]})
|> Ecto.Changeset.put_assoc(:todo_items, [todo_item_changeset])
case Repo.insert(changeset) do
{:ok, company} ->
conn
|> put_flash(:info, "TodoList created!")
|> redirect(to: page_path(conn, :index))
{:error, changeset} ->
conn
|> render "new.html", changeset: changeset
end
end
end
于 2016-12-21T11:47:35.287 に答える