Rails路由:name而不是:id url参数

时间:2014-06-15 03:49:39

标签: ruby-on-rails routes

我有一个名为'公司'而不是每个公司的网址都用以下内容表示:id我想让网址使用他们的名称:url/company/microsoft代替url/company/3

在我的控制器中,我以为我会有

 def show
   @company = Company.find(params[:name])
 end

由于url中没有任何其他参数,我希望rails能理解:name引用了我公司模型中的:name列。我认为这里的魔法会在路线上,但我现在陷入困境。

7 个答案:

答案 0 :(得分:65)

Rails 4.0+的答案很好:

resources :companies, param: :name

您可以选择使用only:except:列表来指定路线

如果你想构建一个URL,你可以覆盖相关模型的ActiveRecord :: Base#to_param:

class Video < ApplicationRecord
  def to_param
    identifier
  end

  # or
  alias_method :to_param, :identifier
end

video = Video.find_by(identifier: "Roman-Holiday")
edit_videos_path(video) # => "/videos/Roman-Holiday"

答案 1 :(得分:11)

<强> params

最重要的是你正在寻找错误的解决方案 - params哈希键是无关紧要的,你需要能够更有效地使用其中包含的数据。

您的路线将构建为:

#config/routes.rb
resources :controller #-> domain.com/controller/:id

这意味着如果您请求此路线:domain.com/controller/your_resource,则params[:id]哈希值将为your_resource(如果它被称为{{1}则无关紧要}或params[:name]

-

<强> friendly_id

您有多个答案推荐params[:id]的原因是因为这会覆盖friendly_id的{​​{1}}方法,允许您在查询中使用slug

find

这允许您这样做:

ActiveRecord

答案 2 :(得分:11)

老实说,我只会覆盖模型中的to_param。这将允许company_path帮助程序正常工作。

注意:我会为复杂的名称创建一个单独的slug列,但这只是我。这是一个简单的案例。

class Company < ActiveRecord::Base
  def to_param
    name
  end
end

然后更改我的路线param以便于阅读。

# The param option may only be in Rails 4+,
# if so just use params[:id] in the controller
resources :companies, param: :name

最后在我的 Controller 中,我需要以正确的方式查找。

class CompaniesController < ApplicationController
  def show
    # Rails 4.0+
    @company = Company.find_by(name: params[:name])
    # Rails < 4.0
    @company = Company.find_by_name(params[:name])
  end
end

答案 3 :(得分:6)

我建议将friendly_id用于此目的。 请注意,friendly_id 4和5之间存在差异。在friendly_id 4中,您可以像这样使用

 @company = Company.find(params[:id])

但是,你无法在friendly_id 5中做到这一点,你必须使用:

 @company = Company.friendly.find(params[:id])

如果您不想使用params [:id]但是params [:name],则必须覆盖routes.rb中的路由。例如

 get '/companies/:name', to: "companies#show"

希望这些信息对您有所帮助

答案 4 :(得分:5)

实现这一点实际上没有什么神奇之处,您必须build it yourself通过在您的模型上正确实施to_param(不推荐)或使用其中一个可用的宝石,如:

我使用friendly_id,它可以很好地完成工作。

答案 5 :(得分:2)

Model.find(primary_key)
这里的默认参数是primary_key id。 如果要使用其他列,则应使用Model.find_by_xxx 所以这里可能是

def show
  @company = Company.find_by_name(params[:name])
end

答案 6 :(得分:0)

:id参数是在请求URL时出现在斜杠之后的内容,因此需要通过检查:id参数是否包含正则表达式和匹配项的非数字值来从中提取名称属性?控制器中的方法。如果存在非数字值,则可以使用为模型生成的rails的find_by_name()方法由name属性分配实例(假设模型具有名为name的属性)

这就是我想出如何使用我的用户资源在应用程序中进行操作的方式。我的用户有一个username属性,我要做的就是修改UsersController,以根据:id参数以不同的方式定义我的@user变量:

private
  # allow routing by name in addition to id
  def get_user
    if params[:id].match?(/\A\d+\Z/)
      # if passed a number, use :id
      @user = User.find(params[:id])
    else
      # if passed a name, use :username
      @user = User.find_by_username(params[:id])
    end
  end

当我创建指向特定用户的链接或在浏览器的地址栏中键入链接时,这使我可以选择使用id或用户名。

然后唯一要做的另一件事是更改视图中的所有链接,以使它们指向具有名称的URL而不是具有ID的URL。

例如,在我更改的导航栏中的link_to()方法调用中

... user_path(current_user) ...

... user_path(current_user.username) ...

在您的示例中,您可能具有以下链接的公司视图:

<%= link_to @company.name, company_path(@company.name) %>

即使当前的公司是Microsoft,即使URL“ companies / 1”仍然有效并且显示的内容与“ companies / Microsoft”相同,也会显示“ Microsoft”并链接到“ companies / Microsoft”。