Ruby-on-rails 使用 :name 而不是 :id url 参数的 Rails 路由
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24226378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails routes with :name instead of :id url parameters
提问by dscher
I have a controller named 'companies' and rather than the urls for each company being denoted with an :id I'd like to have the url use their :name such as: url/company/microsoftinstead of url/company/3.
我有一个名为“公司”的控制器,而不是每个公司的网址都用 :id 表示,我希望网址使用他们的 :name ,例如:url/company/microsoft而不是url/company/3.
In my controller I assumed I would have
在我的控制器中,我假设我会有
def show
@company = Company.find(params[:name])
end
Since there won't be any other parameter in the url I was hoping rails would understand that :name referenced the :name column in my Company model. I assume the magic here would be in the route but am stuck at this point.
由于 url 中不会有任何其他参数,我希望 Rails 能够理解 :name 引用了我公司模型中的 :name 列。我认为这里的魔法会在路线上,但我卡在了这一点上。
采纳答案by Richard Peck
params
params
The bottom line is you're looking at the wrong solution - the paramshash keys are rather irrelevant, you need to be able to use the data contained inside them more effectively.
底线是您正在寻找错误的解决方案 -params散列键相当无关紧要,您需要能够更有效地使用其中包含的数据。
Your routes will be constructed as:
您的路线将被构建为:
#config/routes.rb
resources :controller #-> domain.com/controller/:id
This means if you request this route: domain.com/controller/your_resource, the params[:id]hash value will be your_resource(doesn't matter if it's called params[:name]or params[:id])
这意味着如果您请求此路由:domain.com/controller/your_resource,params[:id]哈希值将是your_resource(无论是调用params[:name]还是调用都无关紧要params[:id])
--
——
The reason you have several answers recommending friendly_idis because this overrides the findmethod of ActiveRecord, allowing you to use a slugin your query:
您有几个推荐答案的原因friendly_id是因为这覆盖了 的find方法ActiveRecord,允许您slug在查询中使用 a :
#app/models/model.rb
Class Model < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: [:slugged, :finders]
end
This allows you to do this:
这允许您执行以下操作:
#app/controllers/your_controller.rb
def show
@model = Model.find params[:id] #-> this can be the "name" of your record, or "id"
end
回答by Matrix
Good answer with Rails 4.0+ :
Rails 4.0+ 的好答案:
resources :companies, param: :name
optionally you can use only:or except:list to specify routes
您可以选择使用only:或except:列出来指定路线
and if you want to construct a URL, you can override ActiveRecord::Base#to_param of a related model:
如果你想构造一个 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"
回答by Azolo
Honestly, I would just overwrite the to_paramin the Model. This will allow company_pathhelpers to work correctly.
老实说,我只想覆盖to_param的模式。这将使company_path助手能够正常工作。
Note: I would create a separate slug column for complex name, but that's just me. This is the simple case.
注意:我会为复杂的名称创建一个单独的 slug 列,但这只是我。这是简单的情况。
class Company < ActiveRecord::Base
def to_param
name
end
end
Then change my routes paramfor readability.
然后更改我的路线param以提高可读性。
# The param option may only be in Rails 4+,
# if so just use params[:id] in the controller
resources :companies, param: :name
Finally in my ControllerI need to look it up the right way.
最后在我的控制器中,我需要以正确的方式查找它。
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
回答by The Lazy Log
I recommend using the friendly_id for this purpose. Please be noted that there are differences between friendly_id 4 and 5. In friendly_id 4, you can use like this
我建议为此目的使用friendly_id。请注意,friendly_id 4 和 5 之间存在差异。在friendly_id 4 中,您可以这样使用
@company = Company.find(params[:id])
However, you won't be able to do that in friendly_id 5, you have to use:
但是,您将无法在friendly_id 5 中执行此操作,您必须使用:
@company = Company.friendly.find(params[:id])
In case that you don't want to use the params[:id] but params[:name], you have to override the route in routes.rb. For example
如果您不想使用 params[:id] 而使用 params[:name],则必须覆盖 routes.rb 中的路由。例如
get '/companies/:name', to: "companies#show"
Hope these info would be helpful to you
希望这些信息对你有帮助
回答by Maurício Linhares
There's actually no magic to implement this, you have to either build it yourselfby correctly implementing to_paramat your model (not recommended) or using one of the gems available for this like:
实际上,实现这一点并没有什么神奇之处,您必须通过在模型中正确实现(不推荐)或使用可用的 gem 之一来自己构建它to_param,例如:
I use friendly_idand it does the job nicely.
我使用friendly_id它,它很好地完成了这项工作。
回答by brick
Model.find(primary_key)
The default parameter here is primary_key id.
If you want to use other columns, you should use Model.find_by_xxx
so here it could be
Model.find(primary_key)
这里的默认参数是primary_key id。如果你想使用其他列,你应该使用 Model.find_by_xxx 所以这里可能是
def show
@company = Company.find_by_name(params[:name])
end
回答by Ethan Groat
The :id parameter is whatever comes after the slash when the URL is requested, so a name attribute needs to be extracted from this by checking the :id parameter for non-numerical values with regular expressions and the match? method in the controller. If a non-numerical value is present, the instance can be assigned by the name attribute using the find_by_name() method that rails generated for the model (assuming that the model has an attribute called name)
:id 参数是请求 URL 时斜杠后面的任何内容,因此需要通过使用正则表达式检查 :id 参数的非数字值和匹配来从中提取名称属性?控制器中的方法。如果存在非数字值,则可以使用 rails 为模型生成的 find_by_name() 方法通过 name 属性分配实例(假设模型具有名为 name 的属性)
That's how I figured out how to do it in my app with my Users resource. My users have a username attribute, and all I had to do was modify the UsersController to define my @user variable differently depending on the :id parameter:
这就是我想出如何使用我的用户资源在我的应用程序中执行此操作的方式。我的用户有一个 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
This gives me the option to use either id or username when I create a link to a particular user, or type it into the browser's address bar.
这使我可以在创建指向特定用户的链接时使用 id 或 username 的选项,或将其键入到浏览器的地址栏中。
Then the only other (optional) thing to do is to change all the links in the views so that they point to the URL with the name instead of the URL with the id.
然后唯一要做的其他(可选)事情是更改视图中的所有链接,以便它们指向带有名称的 URL,而不是带有 id 的 URL。
For example, within the link_to() method call in my navigation bar I changed
例如,在导航栏中的 link_to() 方法调用中,我更改了
... user_path(current_user) ...
to
到
... user_path(current_user.username) ...
In your example, you might have a company view with the following link:
在您的示例中,您可能拥有包含以下链接的公司视图:
<%= link_to @company.name, company_path(@company.name) %>
Which, if the current company is Microsoft, would display "Microsoft" and link to "companies/Microsoft", even though the URL "companies/1" would still be valid and display the same thing as "companies/Microsoft"
其中,如果当前公司是 Microsoft,则将显示“Microsoft”并链接到“公司/Microsoft”,即使 URL“公司/1”仍然有效并显示与“公司/Microsoft”相同的内容

