Rails – link_to,路由和嵌套资源

由于我对嵌套资源的理解,在边缘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 

这样做可以尽职地重定向到PostsControllershow动作,并传递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_toform_for非常相似,它们使用一种常用方法来构建URL,称为url_forurl_for方法采用许多不同种类的对象,例如字符串,哈希值甚至模型实例,如上例所示。

那么它对这些物体的作用非常简洁。 在上面的redirect_to @post调用的情况下,它检查@post对象,看到它是Post类的对象(我们假设,无论如何)并通过调用检查该对象是否已在某个数据库中持久化persisted? 在上面。

通过“持久化”,我的意思是Ruby对象在某个地方的数据库中有匹配的记录。 persisted? Active Record中的方法实现如下:

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

如果对象不是通过诸如Model.new的调用创建的,那么它将不是新记录,如果它没有调用的destroy方法,它也不会被销毁。 如果这两种情况都属实,那么这使得对象很可能以记录的forms持久保存到数据库中。

如果它已被持久化,则url_for知道可以在某处找到此对象,并且可以找到它的位置很可能是在名为post_path的方法下。 所以它调用此方法,并传入此对象的to_param值,该值通常是id

简而言之,它实际上是这样做的:

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

这就是这样的:

 post_path(1) 

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

 "/posts/1" 

可爱!

这称为多态路由 。 您可以将对象传递给redirect_tolink_toform_for等方法,它会尝试找出使用内容的正确URL。

form_for的forms

现在,当你编写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的请求将posts_pathcreate操作,而不是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页面中变得越来越普遍。

一种更复杂的forms

因此,当您传递普通对象时, form_for非常简单,但是如果传递一个对象数组会发生什么? 像这样,例如:

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

好吧, url_forform_for都让你也在那里。

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

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

首先,它知道@post对象属于Post类并且是持久的,因此URL助手将以post开头。 其次,它知道@comment对象是Comment类并且没有持久化,因此comments将在URL帮助程序构建中跟随posturl_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总是用于数组中指定的最后一个对象。 之前的对象只是它的嵌套,仅此而已。

添加的对象越多, url_for执行硬码并构建路径的次数就越多……虽然我建议您将其保留为两部分。

象征forms

现在我们已经介绍了使用包含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_tolink_toform_for方法的多态路由的数组forms。 可能还有其他我现在也不记得的方法也可以做到这一点……通常Rails中的任何方法通常都会使用URL。

没有必要使用哈希在任何大于2的Rails版本中构建您的URL; 那是一所非常古老的学校。

相反,尝试一下您对多态路由的新知识,并尽可能地利用它。

这应该工作:

 
  link_to“用户post”,user_posts_path(@user)

欲了解更多详情,请访

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

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. 添加为调用参数,因为活动记录

这构建了良好的帮助方法。

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

link_to’Destroy Comment’,post_comment_path(comment.post,comment)

注意:这是部分所以没有@