在Ecto,我可以很容易地做到这一点:
Repo.get!(Kaderi.Forum, params["id"])
按主键查找记录,默认情况下为id
。
但是,我正在考虑使用slug而不是ID来实现漂亮的URL。我的模型中有一个slug
字段,我可以轻松地使用它在凤凰城生成网址,如下所示:
defmodule Kaderi.Forum do
use Kaderi.Web, :model
@derive {Phoenix.Param, key: :slug}
...
但似乎并不是slug
字段自动查找记录的简单方法。
我可以执行以下操作:
Repo.get_by!(Kaderi.Forum, slug: params["id"])
但似乎应该有一些很好的方法在模型中配置它,这样我就可以自动生成URL,然后通过slugs查找记录而无需触摸控制器。如果我将来改变生成漂亮网址的方式,我就不必再次更新控制器了。
是否有一些整洁的Ecto / Phoenix技巧,我很容易错过这么做?
答案 0 :(得分:4)
如果你的slug包含id(如3-my-page
而不是my-page
),你可以这样做。)
这是为方便起见,此处复制的Ecto.Type文档中的示例:
defmodule Permalink do
@behaviour Ecto.Type
def type, do: :integer
# Provide our own casting rules.
def cast(string) when is_binary(string) do
case Integer.parse(string) do
{int, _} -> {:ok, int}
:error -> :error
end
end
# We should still accept integers
def cast(integer) when is_integer(integer), do: {:ok, integer}
# Everything else is a failure though
def cast(_), do: :error
# When loading data from the database, we are guaranteed to
# receive an integer (as databases are strict) and we will
# just return it to be stored in the model struct.
def load(integer) when is_integer(integer), do: {:ok, integer}
# When dumping data to the database, we *expect* an integer
# but any value could be inserted into the struct, so we need
# guard against them.
def dump(integer) when is_integer(integer), do: {:ok, integer}
def dump(_), do: :error
end
然后,您可以覆盖架构的主键:
defmodule Post do
use Ecto.Schema
@primary_key {:id, Permalink, autogenerate: true}
schema "posts" do
...
end
end
现在,当您拨打Repo.get(Page, "3-my-page")
字符串" 3-my-page"将被转换为整数3(这是模型的主键),并将返回页面。
如果你的slug中没有整数,那么目前没有简单的方法可以做到这一点,你最好继续使用Repo.get_by
。