slugy v1.2.1 Slugy
A Phoenix library to generate slug for your schema fields
Examples
Let’s suppose we have a Post
schema and we want to generate a slug from title
field and save it to the slug
field. To achieve that we need to call slugify/2
following the changeset pipeline passing the desireable field. slugify/2
generates the slug and put it to the changeset.
defmodule Post do
use Ecto.Schema
import Ecto.Changeset
import Slugy, only: [slugify: 2]
embedded_schema do
field(:title, :string)
field(:slug, :string)
end
def changeset(post, attrs) do
post
|> cast(attrs, [:title])
|> slugify(:title)
end
end
Running this code on iex console you can see the slug generated as a new change to be persisted.
iex> Post.changeset(%Post{}, %{title: “A new Post”}).changes %{title: “A new Post”, slug: “a-new-post”}
Slugy just generates a slug if the field’s value passed to slugify/2
comes with a new value to persist in attrs
(in update cases) or if the struct is a new record to save.
Link to this section Summary
Link to this section Functions
Returns a downcased dashed string.
Examples
iex> Slugy.slugify("Vamo que vamo")
"vamo-que-vamo"
Usage
The slugify/2
expects a changeset as a first parameter and an atom on the second one.
The function will check if there is a change on the title
field and if affirmative generates the slug and assigns to the slug
field, otherwise do nothing and just returns the changeset.
iex> Post.changeset(%Post{}, %{title: “A new Post”}).changes %{slug: “a-new-post”, title: “A new Post”}
Slugify from an embedded struct field
In rare cases you need to generate slugs from a field inside a embeded structure that represents a jsonb column on your database.
For example by having a struct like below and we want a slug from data -> title
:
defmodule PostWithEmbeddedStruct do
use Ecto.Schema
import Ecto.Changeset
import Slugy, only: [slugify: 2]
embedded_schema do
field(:data, :map)
field(:slug, :string)
end
def changeset(post, attrs) do
post
|> cast(attrs, [:data])
|> slugify([:data, :title])
end
end
%PostWithEmbeddedStruct{
data: %{title: "This is my AWESOME title", external_id: 1}
}
Just pass a list with the keys following the path down to the desirable field.
iex> PostWithEmbeddedStruct.changeset(%PostWithEmbeddedStruct{}, %{data: %{title: “This is my AWESOME title”}}).changes %{data: %{title: “This is my AWESOME title”}, slug: “this-is-my-awesome-title”}
Custom slug
If you want a custom slug composed for more than one fields e.g. a post title
and the type
like so "how-to-use-slugy-video"
you need to implement the Slug protocol
that extracts the desirable fields to generate the slug.
defmodule Post do
# ...
end
defimpl Slugy.Slug, for: Post do
def to_slug(%{title: title, type: type}) do
"#{title} #{type}"
end
end
So, %Post{title: "A new Post", type: "video"}
with the above Slug
protocol implementation will have a slug like so a-new-post-video
Routes
And lastly for having our routes with the slug we just need to implement the Phoenix.Param
protocol to our slugified schemas. Phoenix.Param
will extract the slug in place of the :id
.
defmodule Post do
@derive {Phoenix.Param, key: :slug}
schema "posts" do
# ...
end
def changeset(post, attrs) do
# ...
end
end
For more information about Phoenix.Param
protocol see in https://hexdocs.pm/phoenix/Phoenix.Param.html
Installation
Add to your mix.exs
file.
def deps do
[
{:slugy, "~> 1.2.1"}
]
end
Don’t forget to update your dependencies.
$ mix deps.get