Ruby-on-rails Rails - link_to、路由和嵌套资源
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1548009/
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 - link_to, routes and nested resources
提问by knoopx
As my understanding on nested resources, on edge Rails, should not
正如我对嵌套资源的理解,在边缘 Rails 上,不应该
link_to 'User posts', @user.posts
point to
指向
/users/:id/posts
?
?
The routes.rb file contains
route.rb 文件包含
map.resources :users, :has_many => :posts
If this is not the default behavior, can it be accomplished doing something else?
如果这不是默认行为,是否可以通过其他方式完成?
回答by Ryan Bigg
Along the same lines as Rishav:
与 Rishav 相同:
link_to "User Posts", [@user, :posts]
Here's an explanation from my blog.
这是我博客中的解释。
Really early on in Rails, you would write routes like this:
在 Rails 的早期,你会写这样的路由:
redirect_to :controller => "posts", :action => "show", :id => @post.id
What this would do is dutifully redirect to the showaction inside the PostsControllerand pass along the idparameter with a
value of whatever @post.idreturns. Typical 302 response.
这将做的是尽职尽责地重定向到show里面的动作,PostsController并传递id带有任何@post.id返回值的参数。典型的 302 响应。
Then Rails 1.2 came along and allowed you to use routing helpers, like this:
然后 Rails 1.2 出现并允许您使用路由助手,如下所示:
redirect_to post_path(@post)
And the people rejoiced.
人民欢欣鼓舞。
This would do effectively the same thing. post_pathhere would build a route using the @postobject that would look something
like /posts/1and then redirect_towould send back a 302 response to that route and the browser would follow it.
这将有效地做同样的事情。post_path这里将使用@post看起来像这样的对象构建一个路由/posts/1,然后redirect_to向该路由发送回 302 响应,浏览器将遵循它。
Then later versions (I can't remember which one), allowed syntax like this:
然后后来的版本(我不记得是哪一个),允许这样的语法:
redirect_to @post
And the people rejoiced a second time.
人们第二次欢欣鼓舞。
Magic, but not really
魔术,但不是真的
Any sufficiently advanced technology is indistinguishable from magic.
任何足够先进的技术都与魔法无异。
While this seems like magic, it's not. What this is doing is actually very, very neat. The redirect_tomethod, much like its cousins link_toand form_forall use a common method to build URLs, called url_for. The url_formethod takes many different
varieties of objects, such as strings, hashes or even instances of models, like in the example above.
虽然这看起来很神奇,但事实并非如此。这实际上非常非常整洁。该redirect_to方法与它的同类方法非常相似link_to,form_for都使用一种通用方法来构建 URL,称为url_for. 该url_for方法采用许多不同种类的对象,例如字符串、散列甚至模型实例,如上例所示。
What it does with these objects then, is quite neat. In the case of the redirect_to @postcall above, it inspects the @postobject, sees that it is an object of the Postclass (we assume, anyway) and checks to see if that object has been persisted in a
database somewhere by calling persisted?on it.
它对这些对象的处理非常简洁。在上述redirect_to @post调用的情况下,它检查@post对象,看到它是Post类的对象(我们假设,无论如何)并通过调用persisted?它来检查该对象是否已保存在数据库中的某处。
By "persisted", I mean that a Ruby object has a matching record in the database somewhere. The persisted?method in Active Record is implemented like this:
通过“持久化”,我的意思是 Ruby 对象在数据库中的某处有匹配的记录。persisted?Active Record 中的方法是这样实现的:
def persisted?
!(new_record? || destroyed?)
end
If the object wasn't created through a call such as Model.newthen it won't be a new record, and if it hasn't had the destroymethod called on it won't be
destroyed either. If both of these cases are true, then that makes the object has most likely been persistedto the database in the form of a record.
如果对象不是通过调用创建的,Model.new那么它不会是一个新记录,如果它没有destroy调用方法,它也不会被销毁。如果这两种情况都为真,那么这使得对象很可能以记录的形式持久化到数据库中。
If it has been persisted, then url_forknows that this object can be found
somewhere, and that the place it can be found is most likely under a method called post_path. So it calls this method, and passes
in the to_paramvalue of this object which is usually the id.
如果它已经被持久化了,那么就url_for知道这个对象可以在某处找到,并且可以找到它的地方很可能在一个名为 的方法下post_path。所以它调用这个方法,并传入to_param这个对象的值,通常是id.
In short, it's effectively doing this:
简而言之,它有效地做到了这一点:
#{@post.class.downcase}_path(@post.to_param)
Which comes out to being this:
结果是这样的:
post_path(1)
And when that method is called you would get this little string:
当该方法被调用时,你会得到这个小字符串:
"/posts/1"
Lovely!
迷人的!
This is called polymorphic routing. You can pass an object to methods like redirect_to, link_toand form_forand it will
attempt to work out the correct URL of what to use.
这称为多态路由。你可以传递一个对象类似的方法redirect_to,link_to并且form_for,它会试图制定出使用何种正确的URL。
The form of form_for
form_for 的形式
Now, when you're coding Rails you may have used form_forlike this a very long time ago:
现在,当您编写 Rails 代码时,您可能form_for很久以前就这样使用过:
<% form_for @post, :url => { :controller => "posts", :action => "create" } do |f| %>
Of course, with advancements in Rails you could simplify it to this:
当然,随着 Rails 的进步,您可以将其简化为:
<% form_for @post, :url => posts_path do |f| %>
Because the form is going to default to having a POSTHTTP method and therefore a request to posts_pathis going to go to the
createaction of PostsController, rather than the indexaction, which is what would result if it were a GETrequest.
因为表单将默认具有POSTHTTP 方法,因此请求posts_path将转到 的
create操作PostsController,而不是index操作,如果它是GET请求,则会导致结果。
But why stop there? Why not just write this?
但为什么要停在那里?为什么不写这个?
<%= form_for @post do |f| %>
Personally, I see no reason not to... if it's something as simple as this. The form_formethod uses url_forunderneath, just like
redirect_toto work out where the form should go. It knows that the @postobject is of the Postclass (again, we assume) and it
checks to see if the object is persisted. If it is, then it will use post_path(@post). If it's not, then posts_path.
就个人而言,我认为没有理由不...如果事情像这样简单。该form_for方法url_for在下面使用,就像
redirect_to计算表单应该去哪里一样。它知道该@post对象属于Post该类(我们再次假设)并检查该对象是否被持久化。如果是,那么它将使用post_path(@post). 如果不是,那么posts_path。
The form_formethod itself checks to see if the object passed in is persisted also, and if it is then it'll default to a PUTHTTP
method, otherwise a POST.
该form_for方法本身会检查传入的对象是否也被持久化,如果是,则默认为PUTHTTP 方法,否则为POST.
So this is how form_forcan be flexible enough to have an identical syntax on both a newand editview. It's becoming more and
more common these days for people to even put their whole form_fortags into a single partial and include it in both the newand
editpages.
所以这就是如何form_for足够灵活以在 anew和editview上使用相同的语法。如今,人们甚至将整个form_for标签放入单个部分并将其包含在new和
edit页面中变得越来越普遍。
A more complex form
更复杂的形式
So form_foris fairly simple for when you pass a normal object, but what happens if you pass an array of objects? Like this, for
instance:
所以form_for当你传递一个普通对象时相当简单,但是如果你传递一个对象数组会发生什么?像这样,例如:
<%= form_for [@post, @comment] do |f| %>
Well, both url_forand form_forhave you covered there too.
同时,双方url_for并form_for已为你披上也在那里。
The url_formethod detects that this is an array and separates out each part and inspects them individually. First, what is this
@postthing? Well, in this case let's assume it's a Postinstance that ispersisted and has the id of 1. Second, what is this
@commentobject? It's a Commentinstance that has not yet been persisted to the database.
该url_for方法检测到这是一个数组并分离出每个部分并单独检查它们。首先,这是什么
@post东西?那么,在这种情况下,我们假设它是Post该实例是持久和有1秒的ID,这是什么
@comment目的?这是一个Comment尚未持久化到数据库的实例。
What url_forwill do here is build up the URL helper method piece by piece by placing each part in an array, joining it into a routing method and then calling that routing method with the necessary arguments.
什么url_for会在这里做的是通过将每个部分在一个阵列,其连接到路由方法,然后调用建立由一块URL辅助方法,一块路由方法所需的参数。
First, it knows that the @postobject is of the Postclass and is persisted, therefore the URL helper will begin with post. Second, it knows that the @commentobject is of the Commentclass and is notpersisted, and therefore commentswill follow postin the URL helper build. The parts that url_fornow knows about are [:post, :comments].
首先,它知道该@post对象属于Post该类并被持久化,因此 URL 助手将以post. 其次,它知道该@comment对象属于Comment该类并且没有被持久化,因此comments将跟随post在 URL 帮助程序构建中。url_for现在知道的部分是[:post, :comments].
The url_formethod combines these individual parts with an underscore, so that it becomes post_commentsand then appends _pathto the end of that, resulting in post_comments_path. Then it passes in just the persisted objects to the call to that method, resulting in a call like this:
该url_for方法将这些单独的部分与一个下划线组合在一起,使其成为post_comments,然后附加_path到它的末尾,从而产生post_comments_path. 然后它只将持久化对象传递给对该方法的调用,从而产生如下调用:
post_comments_path(@post)
Calling that method results in this:
调用该方法会导致:
"/posts/1/comments"
Best part? form_forwill still know to use POSTif the @commentobject is not a persisted object, and PUTif it is. A good
thing to remember is that the form_foris always for the lastobject specified in the array. The objects prior to it are just its
nesting, nothing more.
最好的部分?如果对象不是持久化对象,form_for则仍然知道使用,如果是。需要记住的一件好事是,总是用于数组中指定的最后一个对象。它之前的对象只是它的嵌套,仅此而已。POST@commentPUTform_for
The more objects that are added, the more times url_forwill do the hard yards and build the path out... although I recommend that
you keep it to just two parts.
添加的对象越多,越多的时间url_for会做硬码并构建路径......尽管我建议您将其保留为两部分。
A symbolic form
象征形式
Now that we've covered using an array containing objects for form_for, let's take a look at another common use. An array containing
at least one Symbol object, like this:
既然我们已经介绍了使用包含对象的数组 for form_for,让我们看一下另一个常见用法。一个包含至少一个 Symbol 对象的数组,如下所示:
<%= form_for [:admin, @post, @comment] do |f| %>
What the url_formethod does here is very simple. It sees that there's a Symboland takes it as it is. The first part of the
urlwill simply be the same as the symbol: admin. The URL that url_forknows of at this point is just [:admin].
该url_for方法在这里所做的非常简单。它看到有一个Symbol并照原样接受它。的第一部分
url将与符号相同:admin。此时url_for知道的 URL就是[:admin].
Then url_forgoes through the remaining parts of the array. In this case, let's assume both @postand @commentare persisted
and that they have the ids of 1 and 2 respectively. Same classes as before. url_forthen adds postto the URL that it's building,
and commenttoo, resulting in [:admin, :post, :comment].
然后url_for遍历数组的其余部分。在这种情况下,让我们假设@post和@comment都被持久化,并且它们的 id 分别为 1 和 2。和以前一样的课。url_for然后添加post到它正在构建的 URL 中,并且comment也生成[:admin, :post, :comment].
Then the joining happens, resulting in a method of admin_post_comment_path, and because both @postand @commentare persisted here,
they're passed in, resulting in this method call:
然后连接发生,产生一个方法admin_post_comment_path,并且因为@post和@comment都在这里持久化,所以它们被传入,导致这个方法调用:
admin_post_comment_path(@post, @comment)
Which (usually) turns into this path:
这(通常)变成这条路:
/admin/posts/1/comments/2
You can use the array form of polymorphic routing with the redirect_to, link_toand form_formethods. There's probably other
methods that I'm not remembering right now that can do it too... it's generally anything in Rails that would normally take a URL.
您可以通过redirect_to,link_to和form_for方法使用多态路由的数组形式。可能还有其他我现在不记得的方法也可以做到这一点......它通常是 Rails 中通常需要 URL 的任何东西。
There's no need to build your URLs in any Rails version greater-than 2 using hashes; that's pretty old school.
无需使用哈希在任何大于 2 的 Rails 版本中构建您的 URL;那是相当古老的学校。
Instead, experiment with your new knowledge of polymorphic routing and use it to the best of your advantage.
相反,尝试使用您对多态路由的新知识并充分利用它。
回答by Rishav Rastogi
This should work:
这应该有效:
link_to "User Posts", user_posts_path(@user)
for more details visit:
欲了解更多详情,请访问:
回答by Chloe
This is how to link to a nested resource in the latest Rails:
这是如何链接到最新 Rails 中的嵌套资源:
link_to 'Destroy Comment', post_comment_path(comment.post, comment)
link_to '销毁评论', post_comment_path(comment.post, comment)
Note: This is in a partial so there isn't a @.
注意:这是部分内容,因此没有@.

