与 Rishav 的思路相同:
link_to "User Posts", [@user, :posts]
这是来自my blog的解释。
在 Rails 的早期,你会这样编写路由:
redirect_to :controller => "posts", :action => "show", :id => @post.id
这样做会尽职尽责地重定向到 PostsController 内的 show 操作,并使用 id 参数传递
@post.id 返回的任何值。典型的 302 响应。
然后 Rails 1.2 出现并允许您使用路由助手,如下所示:
redirect_to post_path(@post)
人们很高兴。
这将有效地做同样的事情。 post_path 这里将使用 @post 对象构建一条看起来像东西的路线
比如/posts/1,然后redirect_to会向该路由发回一个302响应,浏览器会跟随它。
后来的版本(我不记得是哪一个了),允许这样的语法:
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、link_to 和 form_for 等方法,它会
尝试找出使用内容的正确 URL。
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 足够灵活以在new 和edit 视图上具有相同语法的方式。它变得越来越
如今,人们甚至将整个 form_for 标签放在一个部分中并将其包含在 new 和
edit 页。
更复杂的形式
所以form_for 在传递普通对象时相当简单,但如果传递对象数组会发生什么?像这样,对于
实例:
<%= form_for [@post, @comment] do |f| %>
嗯,url_for 和 form_for 你也有报道。
url_for 方法检测到这是一个数组并分离出每个部分并单独检查它们。首先,这是什么
@post 东西?好吧,在这种情况下,我们假设它是一个 Post 实例,is 持续存在并且 id 为 1。其次,这是什么
@comment 对象?这是一个尚未持久化到数据库的Comment 实例。
url_for 将在这里做的是通过将每个部分放在一个数组中,将其连接到一个路由方法中,然后使用必要的参数调用该路由方法,从而逐步构建 URL 帮助器方法。
首先,它知道@post 对象属于Post 类并且是持久的,因此URL 助手将以post 开头。其次,它知道@comment 对象属于Comment 类并且不 持久化,因此comments 将在URL 帮助程序构建中跟随post。 url_for 现在知道的部分是 [:post, :comments]。
url_for 方法将这些单独的部分与下划线组合在一起,使其变为post_comments,然后附加_path
到最后,产生post_comments_path。然后它只将持久化的对象传递给对该方法的调用,从而产生如下调用:
post_comments_path(@post)
调用该方法会导致:
"/posts/1/comments"
最好的部分?如果@comment 对象不是持久对象,form_for 仍然知道使用POST,如果是,则使用PUT。一个好的
要记住的是form_for 始终用于数组中指定的 last 对象。在它之前的对象只是它的
嵌套,仅此而已。
添加的对象越多,url_for 会越多地完成硬码并构建路径......虽然我建议
你只保留两部分。
符号形式
现在我们已经介绍了使用包含 form_for 对象的数组,让我们看看另一个常见的用法。一个数组包含
至少一个 Symbol 对象,像这样:
<%= form_for [:admin, @post, @comment] do |f| %>
url_for 方法在这里所做的非常简单。它看到有一个Symbol 并按原样接受。第一部分
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;那是相当古老的学校。
相反,尝试使用您对多态路由的新知识并充分利用它。