通过主键以外的字段查找记录
Looking up records by a field other than primary key
在 Ecto 中我可以轻松做到这一点:
Repo.get!(Kaderi.Forum, params["id"])
通过主键查找记录,默认为id
。
不过,我正在考虑使用 slug 而不是 ID 来实现漂亮的 URL。我的模型中有一个 slug
字段,我可以很容易地使用它在 Phoenix 中生成 URL,如下所示:
defmodule Kaderi.Forum do
use Kaderi.Web, :model
@derive {Phoenix.Param, key: :slug}
...
但是似乎没有一种简单的方法可以通过 slug
字段自动查找记录。
我可以做如下事情:
Repo.get_by!(Kaderi.Forum, slug: params["id"])
但似乎应该有一些在模型中配置它的好方法,这样我就可以自动生成 URL,然后通过 slugs 查找记录,而无需触摸控制器。如果我以后改变生成漂亮 URL 的方式,我就不必再去更新控制器了。
我是否缺少一些巧妙的 Ecto/Phoenix 技巧来轻松做到这一点?
如果您的 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
.
在 Ecto 中我可以轻松做到这一点:
Repo.get!(Kaderi.Forum, params["id"])
通过主键查找记录,默认为id
。
不过,我正在考虑使用 slug 而不是 ID 来实现漂亮的 URL。我的模型中有一个 slug
字段,我可以很容易地使用它在 Phoenix 中生成 URL,如下所示:
defmodule Kaderi.Forum do
use Kaderi.Web, :model
@derive {Phoenix.Param, key: :slug}
...
但是似乎没有一种简单的方法可以通过 slug
字段自动查找记录。
我可以做如下事情:
Repo.get_by!(Kaderi.Forum, slug: params["id"])
但似乎应该有一些在模型中配置它的好方法,这样我就可以自动生成 URL,然后通过 slugs 查找记录,而无需触摸控制器。如果我以后改变生成漂亮 URL 的方式,我就不必再去更新控制器了。
我是否缺少一些巧妙的 Ecto/Phoenix 技巧来轻松做到这一点?
如果您的 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
.