I may be going about this the wrong way but I can’t seem to figure out a good way to handle input for “tags” in a blog post. I’ve looked at using .inputs_for
but I don’t want to create an input field for every tag. Ideally, it would just be a single text input that spits the value on spaces and transforms those into “tag” structs. Maybe this would be better to do outside a form?
I’ve been messing with it for hours and this doesn’t seem like it should be that difficult. Hopefully someone can point out an easier way I’m missing. Here is what I have right now (back to square one because the handful of things I tried hadn’t worked).
form_component.ex
#...
@impl true
def render(assigns) do
~H"""
<div>
<.header>
<%= @title %>
<:subtitle>by <%= @post.author %></:subtitle>
</.header>
<.simple_form
:let={form}
for={@form}
id="post-form"
as={"post_form"}
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<.input field={@form[:title]} type="text" label="Title" />
<.input field={@form[:tags]} type="text" label="Tags"/> # <<<< This doesn't work, of course.
<.input field={@form[:author]} type="hidden" />
<.input field={@form[:body]} type="textarea" label="Body" />
<:actions>
<.button phx-disable-with="Saving...">Save Post</.button>
</:actions>
</.simple_form>
</div>
"""
end
# ...
post.ex
defmodule Personal.Blog.Post do
use Ecto.Schema
import Ecto.Changeset
schema "posts" do
field :author, :string
field :body, :string
field :title, :string
field :views, :integer, default: 0
many_to_many(:tags, Personal.Blog.Tag, join_through: "post_tags", on_replace: :delete)
timestamps(type: :utc_datetime)
end
@doc false
def changeset(post, attrs) do
post
|> cast(attrs, [:title, :author, :body, :views])
|> validate_required([:title, :author, :body, :views])
end
end
tag.ex
defmodule Personal.Blog.Tag do
use Ecto.Schema
import Ecto.Changeset
schema "tags" do
field :name, :string, default: ""
many_to_many(:posts, Personal.Blog.Post, join_through: "post_tags", on_replace: :delete)
timestamps(type: :utc_datetime)
end
@doc false
def changeset(tag, attrs) do
tag
|> cast(attrs, [:name])
|> validate_required([:name])
end
end
post_tag.ex
defmodule Personal.Blog.PostTag do
use Ecto.Schema
import Ecto.Changeset
schema "post_tags" do
belongs_to(:posts, Personal.Blog.Post)
belongs_to(:tags, Personal.Blog.Tag)
timestamps(type: :utc_datetime)
end
@doc false
def changeset(post_tag, attrs) do
post_tag
|> cast(attrs, [:post_id, :tag_id])
|> validate_required([:post_id, :tag_id])
end
end