You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Phoenix 1.2友好URL Slug问题:旧记录未更新且链接丢失ID参数

搞定Phoenix 1.2旧记录Slug缺失和索引页链接失效问题

你已经把新记录的Slug功能跑通了,但旧数据没触发Slug生成逻辑,加上空Slug导致索引页链接丢参数,这俩问题其实很好解决,分四步来:

1. 先给所有旧记录批量生成Slug

你的Slug是在创建/更新记录时通过changeset生成的,旧数据没走过这个流程,所以得手动补一遍。打开项目目录的IEx控制台(输入iex -S mix),跑这段代码:

Radios.Repo.all(Radios.Radio)
|> Enum.each(fn radio ->
  # 只处理没有Slug的记录
  if is_nil(radio.slug) or radio.slug == "" do
    slug = String.downcase(radio.name) |> String.replace(" ", "-")
    # 用Ecto.Changeset.change直接更新Slug
    Radios.Repo.update!(Ecto.Changeset.change(radio, slug: slug))
  end
end)

跑完所有旧记录就都有Slug了。

2. 优化Changeset,确保更新时Slug也能同步

现在你的slug_map只从传入的params里拿name,如果更新记录时没传name参数,Slug不会跟着更新(比如只改价格的情况)。改一下逻辑,优先用params的name,没有的话就用记录本身的name:

# 重写slug_map,把struct传进来
defp slug_map(params, struct) do
  # 优先取params里的name,没有就用原记录的name
  name = Map.get(params, "name", struct.name)
  if name do
    slug = String.downcase(name) |> String.replace(" ", "-")
    %{"slug" => slug}
  else
    %{}
  end
end

# 然后修改changeset函数,把struct传给slug_map
def changeset(struct, params \\ %{}) do
  params = Map.merge(params, slug_map(params, struct))
  struct
  |> cast(params, [:name, :desc, :price, :text1, :text2, :text3, :text4, :mainimg, :mainimg2, :slug])
  |> validate_required([:name, :desc, :price, :text1, :text2, :mainimg])
end

这样以后不管是创建还是更新,只要name有值,Slug都会自动生成或更新。

3. 给Phoenix.Param加个兜底,避免空链接

万一还有记录没生成Slug(比如name为空的极端情况),索引页会生成空链接,导致show方法拿不到id。修改Phoenix.Param的实现,当Slug为空时自动用记录的id代替:

defimpl Phoenix.Param, for: Radios.Radio do
  def to_param(%{slug: slug, id: id}) do
    # 有Slug用Slug,没有就用id
    if slug && slug != "", do: slug, else: to_string(id)
  end
end

同时,show方法也要兼容两种查询方式(Slug或id),不然用id访问会报错:

def show(conn, %{"id" => id}) do
  radio = 
    case Integer.parse(id) do
      # 如果是数字,按id查
      {int_id, _} -> Repo.get!(Radio, int_id)
      # 不是数字,按Slug查
      :error -> Repo.get_by!(Radio, slug: id)
    end
  render(conn, "show.html", radio: radio)
end

这样不管链接是带Slug还是id,都能正常找到记录。

4. 确认模板里的路由助手用对了

最后检查一下索引页的模板(比如web/templates/radio/index.html.eex),确保链接是用Phoenix的路由助手生成的,比如:

<%= link radio.name, to: radio_path(@conn, :show, radio) %>

不要硬写URL,路由助手会自动调用Phoenix.Param的to_param方法生成正确的链接。


内容的提问来源于stack exchange,提问作者Simon Cooper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:25:57