如何构建一个带有字符串ID而不是数字ID的link_to标记?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何构建一个带有字符串ID而不是数字ID的link_to标记?相关的知识,希望对你有一定的参考价值。

我有一个关于Rails 5的路由问题。我在config / routes.rb文件中有这个

  resources :votes

我的VotesController中的“show”方法可以采用数字或字符串形式的ID。

  def show
    id = params[:id]
    if id.present?
      # If they entered a name
      if id.to_i == 0
        name = id.gsub "_", " "
        @person = Person.find_by_name(name)
      else
        @person = Person.find_by_id(id)
      end

我曾经能够构建这个link_to链接到方法来生成一个带有数字ID的链接...

<%= link_to person.name, vote_path(person), :class => 'unvotedPersonLink' %>

但是,我想生成一个带有ID字符串值的链接,由我的模型中名为“person.seo_name”的方法定义。所以我尝试了这个

<%= link_to person.name, vote_path(:id => person.seo_name), :class => 'unvotedPersonLink' %>

但得到了错误

No route matches {:action=>"show", :controller=>"votes", :id=>nil} missing required keys: [:id]

如何构建我的link_to标记,以便它传递我想要的“字符串”参数而不是数字参数?

答案

你可以传递你想要的任何东西。如果错误告诉您传递的ID是nil,那么您使用的seo_namePerson属性是nil

只要vote_path期待一个ID,您可以通过rake routes | grep vote查看,那么只要生成一个链接就可以正常工作:

<%= link_to person.name, vote_path(person.seo_name) %>

但请记住,它需要您在控制器中进行必要的调整,以便根据persons列而不是seo_name搜索id表。


此外,我强烈建议你utilize a gem称为friendly_id为你想要完成的。它会使事情变得更加清洁和干燥,因为您可以在任何模型中轻松使用它。只需将friendly添加到查询中,您就可以轻松使用ID或URL友好的slug来查询表格:

Person.friendly.find(1)

# OR #

Person.friendly.find('this-is-a-url-friendly-string')
另一答案

在你看来

<%= link_to person.name, vote_path(person), :class => 'unvotedPersonLink' %>

要么

<%= link_to person.name, vote_path(id: person.seo_name), :class => 'unvotedPersonLink' %>

在你的控制器中

@person = Person.find_by(id: params[:id]) || Person.find_by(name: params[:id])

确保seo_name方法没有返回nil

另一答案

例外来自vote_path,因此我们可以专注于此而不用担心link_to或控制器。

当我遇到这样的路线问题时,我要做的第一件事就是运行rake routes(或现在的rails routes),以确保我有正确的名字。其次,我使用app变量在控制台中玩游戏。例如:

> app.vote_path(1)
 => "/votes/1"
> app.vote_path(id: 1)
 => "/votes/1"
> app.vote_path("foo")
 => "/votes/foo"
> app.vote_path(id: "foo")
 => "/votes/foo"
> app.vote_path(nil)
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"votes", :id=>nil}, possible unmatched constraints: [:id]
> app.vote_path(id: nil)
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"votes", :id=>nil}, possible unmatched constraints: [:id]

你说其他地方你已经检查过person.seo_name没有返回nil,但我会再次检查,但看起来确实是这个问题。试试这个:

p = Person.find 5   # or whatever is the numeric id
app.vote_path(p.seo_name)
另一答案

参数可以包含任何信息,但您必须根据需要在控制器中处理它们。默认情况下,路由需要有一个称为:id的参数。如果您希望在路由中使用其他名称,则可以覆盖默认资源标识符:id

检查rails routing

确保person.seo_name没有返回nil。所以,你可以在before_save模型中使用Person回调。在那里,您可以使用特定数据设置seo_name字段。

class Subscription < ActiveRecord::Base
   before_save :populate_seo_name, on: :create

   private
     def populate_seo_name
       self.seo_name = ...
     end
end
另一答案

这在过去的https://stackoverflow.com/a/26600064/4652075已被回答。

您正在将字符串传递给期望整数的字段,并将其呈现为空。您应该将字符串值传递给期望字符串的字段。如果你的“投票”模型是由ActiveRecord生成的,那么它很可能是一个整数。

在你的情况下:

class Person < ApplicationRecord
  def to_param
    identifier
  end

  # or
  alias_method :to_param, :identifier
end

class VotesController < ApplicationController
  before_action :set_voter

  def show end;

  private

  def set_voter
    if !params[:id]?
      @person = Person.find_by(identifier: params[:seo_name])
    else
      @person = Person.find(params[:id])
    end
  end
end

# in the view
<%= link_to person.name, votes_path(identifier: person.seo_name), class: "whatever" %>

应该管用。

以上是关于如何构建一个带有字符串ID而不是数字ID的link_to标记?的主要内容,如果未能解决你的问题,请参考以下文章

在路线中使用字母数字段而不是 id - Rails

为啥某些文件的组显示数字(看起来像 ID),而不是字母字符串?

使用干净的字符串 url,而不是使用带有 ui-router 的 mongo 对象 id 的 url

Rails 是不是支持带有方法 post 的 link_to?

如何从数据库中输入方法 ID 的输入参数,而不是使用 SQLite 的字段中的数字 - Xamarin

如何在SOAP UI中使用groovy从字符串中提取数字id