2015-07-16 18 views
12

tôi có các mô hình sau:Chèn một mô hình với hiệp hội has_many

# Foo model 
schema "foo" do 
    field :name, :string 
    has_many: :bars, App.Bar 
end 

# App model 
schema "bar" do 
    field :name, :string 
    belongs_to: foo, App.Foo 
end 

Và hình thức này:

# form.html (Foo) 
<%= form_for @changeset, @action, fn f -> %> 
    <%= text_input f, :name, class: "form-control" %> 
    <%= submit "Submit", class: "btn btn-primary" %> 
<% end %> 

Bên trong mẫu đơn này, làm thế nào tôi có thể thêm các trường văn bản để cư trú của tôi mới Foo với Bars ?

Sau đây không làm việc vì bars không được cài đặt sẵn:

<%= text_input f, :bars, class: "form-control" %> 

Tôi có đi đúng hướng? Nếu vậy làm cách nào tôi có thể tải trước Bars trong biểu mẫu?

Update, điều khiển:

def new(conn, _params) do 
    changeset = %Foo{} |> Repo.preload(:bars) |> Foo.changeset 
    render(conn, "new.html", changeset: changeset) 
end 

def create(conn, %{"foo" => foo_params}) do 
    changeset = %Foo{} |> Repo.preload(:bars) |> Foo.changeset(foo_params) 

    if changeset.valid? do 
    Repo.insert!(changeset) 

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

Các nạp trước dường như làm việc, nhưng tôi nhận được một Argument error khi đạt <%= text_input f, :bars, class: "form-control" %>:

[error] #PID<0.280.0> running App.Endpoint terminated 
Server: 192.168.48.202:4000 (http) 
Request: GET/
** (exit) an exception was raised: 
    ** (ArgumentError) argument error 
     :erlang.bit_size([]) 
     (phoenix_html) lib/phoenix_html/tag.ex:66: anonymous fn/2 in Phoenix.HTML.Tag.tag_attrs/1 
     (elixir) lib/enum.ex:1261: Enum."-reduce/3-lists^foldl/2-0-"/3 
     (phoenix_html) lib/phoenix_html/tag.ex:35: Phoenix.HTML.Tag.tag/2 
     (app) web/templates/foo/form.html.eex:16: anonymous fn/1 in App.FooView.form.html/1 
     (phoenix_html) lib/phoenix_html/form.ex:181: Phoenix.HTML.Form.form_for/4 
     (app) web/templates/foo/form.html.eex:1: App.FooView."form.html"/1 
     (app) web/templates/foo/new.html.eex:3: App.FooView."new.html"/1 
+0

Trình điều khiển của bạn trông như thế nào? Bạn có thể preload Bars vào dữ liệu Foo ở đó với một cái gì đó như '' 'foo = Foo |> Repo.get (id) |> Repo.preload ([: bars])' '' giả sử bạn đang sử dụng Ecto và điều này là để hiển thị một thanh duy nhất. Sau đó, sử dụng vòng lặp for trong mẫu để truy cập từng foo.bar –

+0

Tác vụ là # new/# create, chứ không phải #show. Đã cập nhật câu hỏi bằng cách tải trước 'Thanh'. – Kernael

+0

@Kernael, bạn có thể đăng lỗi đầy đủ trong câu hỏi của mình không? –

Trả lời

12

Xem bài đăng của Jose trên Working with Associations and Embeds để có ví dụ rõ ràng bằng cách sử dụng ToDoLists và ToDoItems (cụ thể là phần có tiêu đề "Liên kết lồng nhau và nhúng"). Ví dụ bên dưới là ví dụ dẫn xuất phản ánh sự kết hợp của bạn của Foos với Thanh.

Để bắt đầu, bạn đang đi đúng hướng với:
has_many: :bars, App.Bar

Sửa đổi hình thức của bạn để phản ánh:

# form.html (Foo) 
<%= form_for @changeset, @action, fn f -> %> 
    <%= text_input f, :name, class: "form-control" %> 
    <%= inputs_for f, :bars, fn i -> %> 
    <div class="form-group"> 
     <%= label i, :name, "Bar ##{i.index + 1}", class: "control-label" %> 
     <%= text_input i, :name, class: "form-control" %> 
    </div> 
<% end %> 
    <%= submit "Submit", class: "btn btn-primary" %> 
<% end %> 

này sử dụng các chức năng inputs_for/4 từ Phoenix.HTML.Form để tạo ra các lĩnh vực cho bạn: liên kết thanh. Ở đây chúng tôi đã gắn nhãn mỗi tuần tự, "Bar # 1" và "Bar # 2" cũng như các thẻ text_input được cung cấp cho mỗi thẻ.

Bây giờ, bạn phải điều chỉnh của bộ điều khiển của bạn newcreate hành động để phản ánh sự bao gồm của một số quán bar (giả sử hai ví dụ):

def new(conn, _params) do 
    changeset = %Foo{} |> Foo.changeset(%Foo{bars: [%MyApp.Bar{}, %MyApp.Bar{}]}) 
    render(conn, "new.html", changeset: changeset) 
end 

def create(conn, %{"foo" => foo_params}) do 
    changeset = %Foo{} |> Foo.changeset(foo_params) 

    case Repo.insert(changeset) do 

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

bạn editupdate hành động này sẽ cần phải tải trước các quán bar :

foo = Repo.get!(Foo, id) |> Repo.preload(:bars) 
2

Nếu mô hình của bạn đã lồng hiệp hội bạn có thể sử dụng inputs_for để đính kèm dữ liệu lồng vào biểu mẫu. Ví dụ: vui lòng xem here trong Các đầu vào được lồng vào Mục.

Các vấn đề liên quan