正如我对边缘 Rails 上的嵌套资源的理解,不应该
link_to 'User posts', @user.posts
指向
/users/:id/posts
?
routes.rb 文件包含
map.resources :users, :has_many => :posts
如果这不是默认行为,是否可以通过其他方式完成?
正如我对边缘 Rails 上的嵌套资源的理解,不应该
link_to 'User posts', @user.posts
指向
/users/:id/posts
?
routes.rb 文件包含
map.resources :users, :has_many => :posts
如果这不是默认行为,是否可以通过其他方式完成?
与 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/1
redirect_to
然后后来的版本(我不记得是哪一个),允许这样的语法:
redirect_to @post
百姓又欢喜了。
任何足够先进的技术都与魔法无异。
虽然这看起来很神奇,但事实并非如此。这实际上是非常非常整洁的。该redirect_to
方法与它的表亲一样link_to
,form_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_to
form_for
现在,当你在编写 Rails 时,你可能form_for
很久以前就这样使用过:
<% form_for @post, :url => { :controller => "posts", :action => "create" } do |f| %>
当然,随着 Rails 的进步,您可以将其简化为:
<% form_for @post, :url => posts_path do |f| %>
因为表单将默认使用POST
HTTP 方法,因此请求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
方法本身检查传入的对象是否也被持久化,如果是,则默认为PUT
HTTP 方法,否则为POST
.
所以这就是如何form_for
足够灵活地在 anew
和edit
view 上拥有相同的语法。form_for
如今,人们甚至将整个标签放在一个部分中并将其包含在 thenew
和
edit
页面中变得越来越普遍。
所以form_for
当你传递一个普通对象时相当简单,但是如果你传递一个对象数组会发生什么呢?像这样,例如:
<%= form_for [@post, @comment] do |f| %>
好吧,两者都有url_for
,form_for
你也有报道吗?
该url_for
方法检测到这是一个数组并分离出每个部分并单独检查它们。首先,这是什么
@post
东西?好吧,在这种情况下,让我们假设它是一个持久Post
化的实例,其 id 为 1。其次,这个
对象是什么?这是一个尚未持久化到数据库的实例。@comment
Comment
在这里url_for
要做的是通过将每个部分放在一个数组中,将它加入到路由方法中,然后使用必要的参数调用该路由方法,从而逐步构建 URL 辅助方法。
首先,它知道该@post
对象属于Post
该类并且是持久的,因此 URL 帮助程序将以post
. 其次,它知道该@comment
对象属于Comment
该类并且没有持久化,因此comments
将post
在 URL 帮助程序构建中遵循。url_for
现在知道的部分是[:post, :comments]
。
该url_for
方法将这些单独的部分与下划线组合在一起,使其变为post_comments
然后附加_path
到其末尾,从而产生post_comments_path
. 然后它只将持久化的对象传递给对该方法的调用,从而产生如下调用:
post_comments_path(@post)
调用该方法会导致:
"/posts/1/comments"
最好的部分?如果对象不是持久对象,并且如果是,form_for
仍然会知道使用。要记住的一件好事是 总是针对数组中指定的最后一个对象。它之前的对象只是它的嵌套,仅此而已。POST
@comment
PUT
form_for
添加的对象越多,越多的时间url_for
将完成硬码并构建路径......尽管我建议您将其保留为仅两部分。
现在我们已经介绍了使用包含对象的数组 for form_for
,让我们看看另一种常见的用法。包含至少一个 Symbol 对象的数组,如下所示:
<%= form_for [:admin, @post, @comment] do |f| %>
该url_for
方法在这里所做的非常简单。它看到有 aSymbol
并照原样接受它。的第一部分
url
将与符号相同:admin
。url_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_to
和form_for
方法一起使用。可能还有其他我现在不记得的方法也可以做到这一点……通常是 Rails 中通常采用 URL 的任何方法。
无需使用哈希在任何大于 2 的 Rails 版本中构建 URL;那是相当古老的学校。
相反,尝试使用您对多态路由的新知识,并充分利用它。
这应该有效:
link_to "用户帖子", user_posts_path(@user)
欲了解更多详情,请访问:
link_to
使用url_for
哪个使用polymorphic_url
。
polymorphic_url
:
因此,正如其他人所说,您应该使用:
link_to 'User Posts', [@user, :posts]
路径是:
user_posts_path(@user)
^^^^ ^^^^^ ^^^^^
1 2 3
@user
因为它是一个活动记录这构建了好帮手方法。
这是如何链接到最新 Rails 中的嵌套资源:
link_to '销毁评论', post_comment_path(comment.post, comment)
注意:这是部分内容,因此没有@
.