【问题标题】:Looking up records by a field other than primary key通过主键以外的字段查找记录
【发布时间】:2016-04-07 21:05:26
【问题描述】:

在 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 技巧来轻松做到这一点?

【问题讨论】:

  • 我不确定我是否完全理解您希望实现的“理想”解决方案是什么,但是使用 get _by 有什么问题?与此类似的解决方案是否让您满意? stackoverflow.com/questions/34570612/…
  • @Wobbley 理想的解决方案是使用一行代码来配置模型以通过 slug 而不是 id 来查找记录。我不必更改视图以使用 slug 呈现链接,因此我必须更改控制器才能使用它们似乎有点奇怪。
  • 基本上我知道id 的查找不是硬编码的,因为如果您更改模型中的主键,它将使用它。不知道主键部分是不是也是硬编码的,还是可以配置的。
  • @sevenseacat primary_key 部分是基于结构体github.com/elixir-lang/ecto/blob/… 硬编码的,The Programming Phoenix 这本书涵盖了使用自定义 Ecto Type hexdocs.pm/ecto/Ecto.Type.html 作为带有 slug 的主键。它在 slug 中包含 id,例如“13-overriding-primary-key”,与 Ecto.Type 文档中的示例非常相似。
  • 我和你在一起@sevenseacat。我希望能够使用 slug/permalink 创建 URL 助手和路径助手!

标签: phoenix-framework ecto


【解决方案1】:

如果您的 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

【讨论】:

    猜你喜欢
    • 2011-10-21
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 2014-01-19
    相关资源
    最近更新 更多