29

正如我对边缘 Rails 上的嵌套资源的理解,不应该

link_to 'User posts', @user.posts

指向

/users/:id/posts

?

routes.rb 文件包含

map.resources :users, :has_many => :posts

如果这不是默认行为,是否可以通过其他方式完成?

4

4 回答 4

63

与 Rishav 的思路相同:

link_to "User Posts", [@user, :posts]

这是我博客中的解释。

在 Rails 的早期,你会这样写路由:

redirect_to :controller => "posts", :action => "show", :id => @post.id

这样做会尽职尽责地重定向到show内部的操作,PostsController并传递id带有@post.id返回值的参数。典型的 302 响应。

然后 Rails 1.2 出现并允许您使用路由助手,如下所示:

redirect_to post_path(@post)

而人们欢欣鼓舞。

这将有效地做同样的事情。这里将使用看起来像post_path的对象构建一个路由,然后将 302 响应发送回该路由,浏览器将跟随它。@post/posts/1redirect_to

然后后来的版本(我不记得是哪一个),允许这样的语法:

redirect_to @post

百姓又欢喜了。

魔术,但不是真的

任何足够先进的技术都与魔法无异。

虽然这看起来很神奇,但事实并非如此。这实际上是非常非常整洁的。该redirect_to方法与它的表亲一样link_toform_for都使用一种通用方法来构建 URL,称为url_for. 该url_for方法采用许多不同种类的对象,例如字符串、哈希甚至模型实例,如上例所示。

那么,它对这些对象所做的事情非常整洁。在上述redirect_to @post调用的情况下,它检查@post 对象,发现它是Post类的对象(无论如何,我们假设)并通过调用来检查该对象是否已持久保存在某个数据库persisted?中。

“持久化”是指 Ruby 对象在数据库中某处有匹配的记录。Active Record 中的persisted?方法是这样实现的:

def persisted?
  !(new_record? || destroyed?)
end

如果对象不是通过调用创建的,Model.new那么它将不是一个新记录,如果它没有destroy调用该方法,它也不会被销毁。如果这两种情况都成立,那么这使得对象很可能已经以记录的形式被持久化到数据库中。

如果它已经被持久化,那么就url_for知道这个对象可以在某个地方找到,并且它可以找到的地方很可能是在一个名为 的方法下post_path。所以它调用这个方法,并传入to_param这个对象的值,通常是id.

简而言之,它有效地做到了这一点:

#{@post.class.downcase}_path(@post.to_param)

结果是这样的:

post_path(1)

当调用该方法时,您会得到这个小字符串:

"/posts/1"

迷人的!

这称为多态路由。您可以将一个对象传递给类似的方法,redirect_to它会尝试计算出正确的 URL 来使用什么。link_toform_for

form_for 的形式

现在,当你在编写 Rails 时,你可能form_for很久以前就这样使用过:

<% form_for @post, :url => { :controller => "posts", :action => "create" } do |f| %>

当然,随着 Rails 的进步,您可以将其简化为:

<% form_for @post, :url => posts_path do |f| %>

因为表单将默认使用POSTHTTP 方法,因此请求posts_path将转到 的 create操作PostsController,而不是操作,如果它是请求index,这将是什么结果。GET

但为什么要停在那里?为什么不写这个?

<%= form_for @post do |f| %>

就个人而言,我认为没有理由不... 如果事情就这么简单。该form_for方法url_for在下面使用,就像 redirect_to计算表单应该去哪里一样。它知道该@post对象属于Post该类(我们再次假设)并检查该对象是否被持久化。如果是,那么它将使用post_path(@post). 如果不是,那么posts_path

form_for方法本身检查传入的对象是否也被持久化,如果是,则默认为PUTHTTP 方法,否则为POST.

所以这就是如何form_for足够灵活地在 aneweditview 上拥有相同的语法。form_for如今,人们甚至将整个标签放在一个部分中并将其包含在 thenewedit页面中变得越来越普遍。

更复杂的形式

所以form_for当你传递一个普通对象时相当简单,但是如果你传递一个对象数组会发生什么呢?像这样,例如:

<%= form_for [@post, @comment] do |f| %>

好吧,两者都有url_forform_for你也有报道吗?

url_for方法检测到这是一个数组并分离出每个部分并单独检查它们。首先,这是什么 @post东西?好吧,在这种情况下,让我们假设它是一个持久Post化的实例,其 id 为 1。其次,这个 对象是什么?这是一个尚未持久化到数据库的实例。@commentComment

在这里url_for要做的是通过将每个部分放在一个数组中,将它加入到路由方法中,然后使用必要的参数调用该路由方法,从而逐步构建 URL 辅助方法。

首先,它知道该@post对象属于Post该类并且是持久的,因此 URL 帮助程序将以post. 其次,它知道该@comment对象属于Comment该类并且没有持久化,因此commentspost在 URL 帮助程序构建中遵循。url_for现在知道的部分是[:post, :comments]

url_for方法将这些单独的部分与下划线组合在一起,使其变为post_comments然后附加_path 到其末尾,从而产生post_comments_path. 然后它只将持久化的对象传递给对该方法的调用,从而产生如下调用:

post_comments_path(@post)

调用该方法会导致:

"/posts/1/comments"

最好的部分?如果对象不是持久对象,并且如果是,form_for仍然会知道使用。要记住的一件好事是 总是针对数组中指定的最后一个对象。它之前的对象只是它的嵌套,仅此而已。POST@commentPUTform_for

添加的对象越多,越多的时间url_for将完成硬码并构建路径......尽管我建议您将其保留为仅两部分。

一种象征形式

现在我们已经介绍了使用包含对象的数组 for form_for,让我们看看另一种常见的用法。包含至少一个 Symbol 对象的数组,如下所示:

<%= form_for [:admin, @post, @comment] do |f| %>

url_for方法在这里所做的非常简单。它看到有 aSymbol并照原样接受它。的第一部分 url将与符号相同:adminurl_for此时知道的URL就是[:admin].

然后url_for遍历数组的其余部分。在这种情况下,我们假设@post@comment都被持久化,并且它们的 id 分别为 1 和 2。和以前一样的课。url_for然后添加post到它正在构建的 URL 中,comment也导致[:admin, :post, :comment].

然后发生连接,产生一个 的方法admin_post_comment_path,并且因为@post@comment都在这里持久化,所以它们被传入,导致这个方法调用:

admin_post_comment_path(@post, @comment)

哪个(通常)变成这条路:

/admin/posts/1/comments/2

您可以将多态路由的数组形式与redirect_to,link_toform_for方法一起使用。可能还有其他我现在不记得的方法也可以做到这一点……通常是 Rails 中通常采用 URL 的任何方法。

无需使用哈希在任何大于 2 的 Rails 版本中构建 URL;那是相当古老的学校。

相反,尝试使用您对多态路由的新知识,并充分利用它。

于 2009-10-10T22:08:47.353 回答
16

这应该有效:

 
 link_to "用户帖子", user_posts_path(@user)

欲了解更多详情,请访问:

http://guides.rubyonrails.org/routing.html

于 2009-10-10T14:06:37.887 回答
2

link_to使用url_for哪个使用polymorphic_url

polymorphic_url

因此,正如其他人所说,您应该使用:

link_to 'User Posts', [@user, :posts]

路径是:

user_posts_path(@user)
^^^^ ^^^^^      ^^^^^
1    2          3
  1. 类,@user因为它是一个活动记录
  2. 转换为字符串,因为符号
  3. 添加为调用参数,因为活动记录

这构建了好帮手方法。

于 2014-11-09T11:47:03.233 回答
1

这是如何链接到最新 Rails 中的嵌套资源:

link_to '销毁评论', post_comment_path(comment.post, comment)

注意:这是部分内容,因此没有@.

于 2013-10-08T15:28:14.223 回答