Verschachtelte Änderungssätze werden im ecto noch nicht unterstützt: https://github.com/elixir-lang/ecto/issues/618 Sie müssen die Tags selbst speichern.
In den folgenden Codeschnipsel werde ich die tag_ids
auswählen und sie in die Join-Tabelle einfügen, wenn die Post.changeset/2
mir ein gültiges Ergebnis geben. Um die ausgewählten Tags im Formular zu halten, habe ich ein virtuelles Feld hinzugefügt, das wir im Formular lesen und einen Standard einrichten können. Es ist nicht die beste Lösung, aber es funktioniert für mich.
Postcontroller
def create(conn, %{"post" => post_params}) do
post_changeset = Post.changeset(%Post{}, post_params)
if post_changeset.valid? do
post = Repo.insert!(post_changeset)
case Dict.fetch(post_params, "tag_ids") do
{:ok, tag_ids} ->
for tag_id <- tag_ids do
post_tag_changeset = PostTag.changeset(%PostTag{}, %{"tag_id" => tag_id, "post_id" => post.id})
Repo.insert(post_tag_changeset)
end
:error ->
# No tags selected
end
conn
|> put_flash(:info, "Success!")
|> redirect(to: post_path(conn, :new))
else
render(conn, "new.html", changeset: post_changeset)
end
end
PostModel
schema "posts" do
has_many :post_tags, Stackoverflow.PostTag
field :title, :string
field :tag_ids, {:array, :integer}, virtual: true
timestamps
end
@required_fields ["title"]
@optional_fields ["tag_ids"]
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
PostTagModel (JoinTable für viele Vereinigung viele erstellen)
schema "post_tags" do
belongs_to :post, Stackoverflow.Post
belongs_to :tag, Stackoverflow.Tag
timestamps
end
@required_fields ["post_id", "tag_id"]
@optional_fields []
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
PostForm
<%= form_for @changeset, @action, fn f -> %>
<%= if f.errors != [] do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below:</p>
<ul>
<%= for {attr, message} <- f.errors do %>
<li><%= humanize(attr) %> <%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= label f, :title, "Title" %>
<%= text_input f, :title, class: "form-control" %>
</div>
<div class="form-group">
<%= label f, :tag_ids, "Tags" %>
<!-- Tags in this case are static, load available tags from controller in your case -->
<%= multiple_select f, :tag_ids, ["Tag 1": 1, "Tag 2": 2], value: (if @changeset.params, do: @changeset.params["tag_ids"], else: @changeset.model.tag_ids) %>
</div>
<div class="form-group">
<%= submit "Save", class: "btn btn-primary" %>
</div>
<% end %>
Wenn Sie Tags aktualisieren möchten, haben Sie zwei Möglichkeiten.
- Alles löschen und neue Einträge
- Suchen Sie nach Änderungen einzufügen, und halten Sie die vorhandenen Einträge
Ich hoffe, es hilft.
ich meine Modelle basierend auf dem hier gegebenen Beispiel erweitert haben, aber ich habe einige Fragen: In MyApp.Tag Sie „#other Post Felder“ schreiben, ich nehme an, Sie „#other Tag-Felder“ In Zukunft bedeuten Wie würde ich zum Beispiel alle Posts mit einem bestimmten Tag oder allen Tags für einen bestimmten Post abfragen? Ich nehme an, diese vorbereiteten Abfragen sollten in das TagPost-Modell eingefügt werden? Ich denke, was ich frage ist, gibt es irgendwelche "Abkürzungen" oder eine vereinfachte Art, dies zu tun? Oder muss ich eine lange Abfrage manuell schreiben? – Wobbley
@Der Broßoror Wie würden Sie den PostController entsprechend den von Ihnen vorgeschlagenen Änderungen ändern? – helcim