Rails - link_to、路由和嵌套资源 [英] Rails - link_to, routes and nested resources
问题描述
根据我对嵌套资源的理解,在边缘 Rails 上,不应该
As my understanding on nested resources, on edge Rails, should not
link_to 'User posts', @user.posts
指向
/users/:id/posts
?
routes.rb 文件包含
The routes.rb file contains
map.resources :users, :has_many => :posts
如果这不是默认行为,是否可以通过其他方式完成?
If this is not the default behavior, can it be accomplished doing something else?
推荐答案
与 Rishav 相同:
Along the same lines as Rishav:
link_to "User Posts", [@user, :posts]
<小时>
这是我的博客的解释.
在 Rails 的早期,你会写这样的路由:
Really early on in Rails, you would write routes like this:
redirect_to :controller => "posts", :action => "show", :id => @post.id
这样做是尽职地重定向到 PostsController
内的 show
动作,并传递带有 id
参数的@post.id
返回的任何值.典型的 302 响应.
What this would do is dutifully redirect to the show
action inside the PostsController
and pass along the id
parameter with a
value of whatever @post.id
returns. Typical 302 response.
然后 Rails 1.2 出现并允许您使用路由助手,如下所示:
Then Rails 1.2 came along and allowed you to use routing helpers, like this:
redirect_to post_path(@post)
人们欢欣鼓舞.
这将有效地做同样的事情.post_path
在这里将使用 @post
对象构建一个看起来有些东西的路由像 /posts/1
然后 redirect_to
会向该路由发回 302 响应,浏览器会跟随它.
This would do effectively the same thing. post_path
here would build a route using the @post
object that would look something
like /posts/1
and then redirect_to
would send back a 302 response to that route and the browser would follow it.
后来的版本(我不记得是哪个),允许这样的语法:
Then later versions (I can't remember which one), allowed syntax like this:
redirect_to @post
人们再次欢欣鼓舞.
任何足够先进的技术都与魔法无异.
Any sufficiently advanced technology is indistinguishable from magic.
虽然这看起来很神奇,但事实并非如此.这实际上非常非常整洁.redirect_to
方法,很像它的堂兄弟 link_to
和 form_for
都使用一个通用的方法来构建 URL,称为 url_for
.url_for
方法需要许多不同的各种对象,例如字符串、散列甚至模型实例,如上例所示.
While this seems like magic, it's not. What this is doing is actually very, very neat. The redirect_to
method, much like its cousins link_to
and form_for
all use a common method to build URLs, called url_for
. The url_for
method takes many different
varieties of objects, such as strings, hashes or even instances of models, like in the example above.
它对这些对象的处理非常简洁.在上面的 redirect_to @post
调用的情况下,它检查 @post
对象,看到它是 Post
类的对象(我们假设,无论如何)并检查该对象是否已持久化通过在其上调用 persisted?
来访问某个数据库.
What it does with these objects then, is quite neat. In the case of the redirect_to @post
call above, it inspects the @post
object, sees that it is an object of the Post
class (we assume, anyway) and checks to see if that object has been persisted in a
database somewhere by calling persisted?
on it.
持久化"是指 Ruby 对象在数据库中的某处有匹配的记录.Active Record 中的 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:
def persisted?
!(new_record? || destroyed?)
end
如果对象不是通过诸如 Model.new
之类的调用创建的,那么它不会是新记录,如果它没有 destroy
> 调用它的方法不会也毁了.如果这两种情况都成立,那么对象很可能以记录的形式持久化到数据库中.
If the object wasn't created through a call such as Model.new
then it won't be a new record, and if it hasn't had the destroy
method called on it won't be
destroyed either. If both of these cases are true, then that makes the object has most likely been persisted to the database in the form of a record.
如果已经持久化了,那么url_for
就知道可以找到这个对象某处,并且可以找到它的位置很可能在名为 post_path
的方法下.所以它调用这个方法,并通过在这个对象的 to_param
值中,通常是 id
.
If it has been persisted, then url_for
knows 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_param
value of this object which is usually the id
.
简而言之,它有效地做到了这一点:
In short, it's effectively doing this:
#{@post.class.downcase}_path(@post.to_param)
结果是这样的:
post_path(1)
当那个方法被调用时,你会得到这个小字符串:
And when that method is called you would get this little string:
"/posts/1"
可爱!
这称为多态路由.您可以将对象传递给诸如 redirect_to
、link_to
和 form_for
之类的方法,它会尝试找出要使用的内容的正确 URL.
This is called polymorphic routing. You can pass an object to methods like redirect_to
, link_to
and form_for
and it will
attempt to work out the correct URL of what to use.
现在,当您编写 Rails 代码时,您可能很久以前就使用过这样的 form_for
:
Now, when you're coding Rails you may have used form_for
like this a very long time ago:
<% form_for @post, :url => { :controller => "posts", :action => "create" } do |f| %>
当然,随着 Rails 的进步,您可以将其简化为:
Of course, with advancements in Rails you could simplify it to this:
<% form_for @post, :url => posts_path do |f| %>
因为表单将默认具有 POST
HTTP 方法,因此对 posts_path
的请求将转到PostsController
的 create
动作,而不是 index
动作,如果它是一个 GET
请求,将会产生什么结果.
Because the form is going to default to having a POST
HTTP method and therefore a request to posts_path
is going to go to the
create
action of PostsController
, rather than the index
action, which is what would result if it were a GET
request.
但为什么要停在那里?为什么不直接写这个?
But why stop there? Why not just write this?
<%= form_for @post do |f| %>
就我个人而言,我认为没有理由不...如果事情像这样简单.form_for
方法在下面使用 url_for
,就像redirect_to
确定表单的位置.它知道 @post
对象属于 Post
类(再次假设)并且它检查对象是否被持久化.如果是,那么它将使用 post_path(@post)
.如果不是,则 posts_path
.
Personally, I see no reason not to... if it's something as simple as this. The form_for
method uses url_for
underneath, just like
redirect_to
to work out where the form should go. It knows that the @post
object is of the Post
class (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
方法本身会检查传入的对象是否也被持久化,如果是,则默认为 PUT
HTTP方法,否则为 POST
.
The form_for
method itself checks to see if the object passed in is persisted also, and if it is then it'll default to a PUT
HTTP
method, otherwise a POST
.
所以这就是 form_for
如何足够灵活以在 new
和 edit
视图上具有相同的语法.它变得越来越现在更常见的是人们甚至将他们的整个 form_for
标签放入单个部分并将其包含在 new
和编辑
页面.
So this is how form_for
can be flexible enough to have an identical syntax on both a new
and edit
view. It's becoming more and
more common these days for people to even put their whole form_for
tags into a single partial and include it in both the new
and
edit
pages.
所以 form_for
当你传递一个普通对象时相当简单,但是如果你传递一个对象数组会发生什么?像这样,对于实例:
So form_for
is 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 [@post, @comment] do |f| %>
好吧,url_for
和 form_for
也已经涵盖了.
Well, both url_for
and form_for
have you covered there too.
url_for
方法检测到这是一个数组并分离出每个部分并单独检查它们.首先,这是什么@post
东西?好吧,在这种情况下,让我们假设它是一个 Post
实例,is 持久化并且 id 为 1.第二,这是什么@comment
对象?这是一个尚未持久化到数据库的 Comment
实例.
The url_for
method detects that this is an array and separates out each part and inspects them individually. First, what is this
@post
thing? Well, in this case let's assume it's a Post
instance that is persisted and has the id of 1. Second, what is this
@comment
object? It's a Comment
instance that has not yet been persisted to the database.
url_for
在这里要做的是通过将每个部分放在一个数组中,将其连接到一个路由方法中,然后使用必要的参数调用该路由方法,逐个构建 URL 帮助器方法.
What url_for
will 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.
首先,它知道 @post
对象属于 Post
类并且是持久化的,因此 URL 助手将以 post
开头.其次,它知道 @comment
对象属于 Comment
类并且没有持久化,因此 comments
将在 URL 帮助程序构建中遵循 post
.url_for
现在知道的部分是 [:post, :comments]
.
First, it knows that the @post
object is of the Post
class and is persisted, therefore the URL helper will begin with post
. Second, it knows that the @comment
object is of the Comment
class and is not persisted, and therefore comments
will follow post
in the URL helper build. The parts that url_for
now knows about are [:post, :comments]
.
url_for
方法将这些单独的部分用下划线组合起来,使其成为 post_comments
然后附加 _path
到最后,导致 post_comments_path
.然后它只将持久化对象传递给对该方法的调用,从而产生如下调用:
The url_for
method combines these individual parts with an underscore, so that it becomes post_comments
and then appends _path
to 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:
post_comments_path(@post)
调用该方法会导致:
"/posts/1/comments"
最好的部分?如果 @comment
对象不是持久化对象,form_for
仍然会知道使用 POST
,如果它是 PUT
是.一个好的需要记住的是 form_for
总是用于数组中指定的 last 对象.在它之前的对象只是它的嵌套,仅此而已.
Best part? form_for
will still know to use POST
if the @comment
object is not a persisted object, and PUT
if it is. A good
thing to remember is that the form_for
is always for the last object specified in the array. The objects prior to it are just its
nesting, nothing more.
添加的对象越多,url_for
就会越多的次数越多,并构建出路径......尽管我建议这样做你把它分成两部分.
The more objects that are added, the more times url_for
will do the hard yards and build the path out... although I recommend that
you keep it to just two parts.
既然我们已经介绍了使用包含 form_for
对象的数组,让我们看看另一个常见用法.一个包含至少一个 Symbol 对象,像这样:
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:
<%= form_for [:admin, @post, @comment] do |f| %>
url_for
方法在这里所做的非常简单.它看到有一个 Symbol
并按原样接受它.第一部分url
将与符号相同:admin
.url_for
此时知道的 URL 就是 [:admin]
.
What the url_for
method does here is very simple. It sees that there's a Symbol
and takes it as it is. The first part of the
url
will simply be the same as the symbol: admin
. The URL that url_for
knows of at this point is just [:admin]
.
然后 url_for
遍历数组的其余部分.在这种情况下,我们假设 @post
和 @comment
都被持久化了并且它们的 ID 分别为 1 和 2.和以前一样的课.url_for
然后将 post
添加到它正在构建的 URL,和 comment
也是,结果是 [:admin, :post, :comment]
.
Then url_for
goes through the remaining parts of the array. In this case, let's assume both @post
and @comment
are persisted
and that they have the ids of 1 and 2 respectively. Same classes as before. url_for
then adds post
to the URL that it's building,
and comment
too, resulting in [:admin, :post, :comment]
.
然后加入,产生了admin_post_comment_path
的方法,并且因为@post
和@comment
都被持久化到这里,它们被传入,导致此方法调用:
Then the joining happens, resulting in a method of admin_post_comment_path
, and because both @post
and @comment
are persisted here,
they're passed in, resulting in this method call:
admin_post_comment_path(@post, @comment)
哪个(通常)变成这个路径:
Which (usually) turns into this path:
/admin/posts/1/comments/2
<小时>
您可以通过redirect_to
、link_to
和form_for
方法使用多态路由的数组形式.可能还有其他我现在不记得的方法也可以做到这一点……通常在 Rails 中,通常会采用 URL 的任何方法.
You can use the array form of polymorphic routing with the redirect_to
, link_to
and form_for
methods. 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.
无需使用哈希在任何大于 2 的 Rails 版本中构建您的 URL;那是相当古老的学校.
There's no need to build your URLs in any Rails version greater-than 2 using hashes; that's pretty old school.
相反,尝试使用您对多态路由的新知识,并充分利用它.
Instead, experiment with your new knowledge of polymorphic routing and use it to the best of your advantage.
这篇关于Rails - link_to、路由和嵌套资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!