按主键以外的字段查找记录

时间:2016-01-04 09:26:15

标签: phoenix-framework ecto

在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技巧,我很容易错过这么做?

1 个答案:

答案 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