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

时间:2018-02-12 20:31:39

标签: ruby-on-rails model-view-controller routes ruby-on-rails-5 link-to

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

  resources :votes

" show"我的VotesController中的方法可以采用数字或字符串形式的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字符串值的链接,由我的模型中名为&#34; person.seo_name&#34;的方法定义。所以我尝试了这个

<%= 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标记,以便它传递给我想要的&#34;字符串&#34;参数而不是数字?

5 个答案:

答案 0 :(得分:1)

你可以传递任何你想要的东西。如果错误告诉您您传递的ID为nil,那么您使用的seo_name的{​​{1}}属性为Person

只要nil期待您可以通过vote_path查看的ID,那么只要生成链接就可以了,这样就可以了:

rake routes | grep vote

但请注意,它会要求您在控制器中进行必要的调整,以便根据<%= link_to person.name, vote_path(person.seo_name) %> 列而不是persons来搜索您的seo_name表格。

此外,我强烈建议您utilize a gem致电id,了解您要完成的工作。它会让事情变得更加清洁和干燥,因为您可以在任何模型中轻松使用它。您可以轻松地使用ID 一个URL友好的slug来查询您的表格,只需将friendly_id添加到查询中即可:

friendly

答案 1 :(得分:0)

在你看来

<%= 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

答案 2 :(得分:0)

例外来自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)

答案 3 :(得分:0)

params可以包含任何信息,但您必须根据需要在控制器中处理它们。默认情况下,路由需要有一个名为: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

答案 4 :(得分:-1)

过去已经回答过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" %>

应该工作。