根据点击的按钮渲染三个不同的部分

所以我有这样的布局:

家用/ index.html.erb:

All posts All stories

在posts_controller.rb中

我有:

 def index @posts = Post.all respond_to do |format| format.html #looks for views/books/index.html.erb format.js #looks for views/books/index.js.erb end end 

在stories_controller.rb中

我有:

 def index @stories = Story.all respond_to do |format| format.html #looks for views/books/index.html.erb format.js #looks for views/books/index.js.erb end end 

在我的views / posts / index.js.erb中

 $("#content").html(""); 

在我的views / stories / index.js.erb中

 $("#content").html(""); 

我还在views/posts_posts.html.erbviews/posts _posts.html.erb中有_posts.html.erb

发生的事情是,当我点击post按钮时我会呈现视图,但是当我点击故事按钮时,什么都没有呈现?

好的,在进入解决方案之前,让我们了解request-response周期。

当您搜索http://stackoverflow.com时 ,您将从client (您的浏览器)向StackOverflow(SO) server发送请求。 客户端和服务器通过HTTP协议进行通信,如果用户请求服务器知道的内容,则它提供(发送)响应(html,css,js文件)。 浏览器知道如何显示从服务器接收的html内容。 每个浏览器都有自己的样式表( user-agent-stylesheet ),它还将样式应用于从服务器发回的html页面中链接的css文件。 请注意,这一切都是同步发生的,当server正在处理客户端的请求时,浏览器选项卡inactive因为它等待服务器的响应。 单击链接时会发生相同的过程。 它会向服务器创建一个新请求。

服务器的响应可以是HTMLJSONXML等。您可能已经注意到, synchronous通信并不是我们一直想要的。

如果我们发出新的synchronous请求,浏览器会再次获取HTMLCSSJS以及image文件(不要进入缓存)。 我们不希望为每个请求更新整个页面。

通常,只有部分页面在请求后更新,并提供良好的用户体验。

这是Javascript擅长的地方。 它可以异步地向服务器发出请求(网页不会重新加载),还可以使用名为AJAX ( 异步Javascript XML )的内容更新页面的某些部分。

典型的AJAX请求是这样的。 您向服务器发出请求,但这次是异步的,服务器用XML而不是HTML响应, Javascript解析XML文档更新页面的一部分。 尽管它现在被称为AJAX,但是现在,JSON用于跨服务交换信息。

因此,要发出AJAX请求,我们需要一个链接,当单击时发送XMLHttpRequest (异步请求),服务器应该使用JSONXML响应,然后脚本应该解析响应并更新DOM ( 文档对象模型 )。 在Vanilla JS (普通javascript)中发出AJAX请求很复杂,人们通常使用Jqueryajax方法来发出AJAX请求(代码行数较少)。 有关更多信息,请参见http://api.jquery.com/jquery.ajax/ 。

但在rails ,它更容易。 我们可以使用UJS ( Unobtrusive Javascript )发出AJAX请求。 让我们看看它在行动。

要使链接发送AJAX请求,您需要在link_to帮助remote: true中设置remote: true 。 这会在生成的HTML中添加data-remote=true

例如以下的erb

 <%= link_to "All books", books_path, remote: true %> 

生成html

 All books 

好。 现在我们都准备发出一个AJAX请求。 将您的代码修改为

 
<%= link_to posts_path, class:"options btn btn-primary", remote: true do %> All posts <% end %> <%= link_to stories_path, class:"options btn btn-primary", remote: true do %> All stories <% end %> <%= link_to books_path, class:"options btn btn-primary", remote: true do %> All books <% end %>

我假设你有控制器,模型和视图设置。 同时在终端中执行rake routes以查看应用程序的现有路由。 您应该看到以下内容(订单不重要)

 Prefix Verb URI Pattern Controller#Action posts GET /posts(.:format) posts#index stories GET /stories(.:format) stories#index books GET https://stackoverflow.com/books(.:format) books#index 

注意:这里的format对应于返回的格式,可以是htmljsxmljson

在其中一个url_helper中指向posts#index url_helper ,意味着每当在rails应用程序中向服务器发出请求时,它首先到达路由器并被分派到routes.rb指定的相应controller动作。

在这种情况下,如果我们向http://localhost:3000https://stackoverflow.com/books发出请求,请求将被发送到books#index action。 在操作中,您可以从database获取数据并将响应发送到客户端。

由于我们对AJAX感兴趣并且我们已经指定了remote:true ,因此rails会期望将JS响应返回给客户端(即负责动态呈现内容的script )。

我将解释如何处理BooksController的AJAX请求,你可以将相同的想法应用于其他控制器。( postsstories )。

 class BooksController < ApplicationController def index @books = Book.all respond_to do |format| format.html #looks for viewshttps://stackoverflow.com/books/index.html.erb format.js #looks for viewshttps://stackoverflow.com/books/index.js.erb end end #other actions end 

我们在这里所做的就是告诉控制器在客户端请求JS响应时呈现index.js.erb ,或者在HTML响应的情况下呈现index.html.erb 。 当我们没有指定要渲染的文件时,rails如何知道渲染index.html.erbindex.js.erb ? 这是什么铁路受欢迎.Rails遵循Convention Over Configuration 。

实际上, controller根据action名称推断出要呈现的模板。

下一步是使用@books更新#content div。 在添加代码以呈现所有书籍之前,我们需要一个模板来渲染吗? 这是部分进入的地方。部分是可重复使用的view' and a partial in rails is prefixed with '_'. For example: view' and a partial in rails is prefixed with '_'. For example: _books.html.erb is a partial for books` is a partial for

创建部分app/viewshttps://stackoverflow.com/books/_books.html.erb

 <% @books.each do |book| %> 
#Display the fields
<% end %>

现在创建app/viewshttps://stackoverflow.com/books/index.js.erb并添加以下内容:

 $("#content").html("<%= j (render 'books') %>"); 

这个单行将把部分_books.html.erb渲染到#content div中。 等待。 它是如何工作的? 让我们分成几块。

内容<%= %>内的任何内容都是ruby代码。 执行它并替换值代替<%= %>erb模板engline允许你在javascript编写ruby代码。 那么,这有什么用呢?

 <%= j (render 'books') %> 

它将渲染books/_books.html.erb ,从参数中推断出render 。 它返回由_books.html.erb生成的html。

j做什么? 它实际上是escape_javascript方法的别名。 它用于转义从部分_books.html.erb返回的内容。

解释escaping html的原因会使这个答案更长。 我强烈建议你在这个 SO线程中阅读kikito的答案(第3个)。

因此,我们将html从partial传递为字符串(请注意<%= %>周围的引号)到html方法,该方法添加在#content div中。 而已!

我建议您检查服务器日志并浏览Developer工具中的Network选项卡,以深入了解AJAX的工作原理。

对其他控制器( PostsControllerStoriesController )执行相同的StoriesController

希望这可以帮助。

链接必须设置为remote: true ,它们必须指向不同的操作(或相同但接收不同的参数)。

这些动作必须响应js并呈现其js视图。

它会是这样的:

你的观点:

 
<%= link_to 'All Posts', posts_path, class: 'options btn btn-primary', method: :get, remote: true %>
<%= render 'all_posts' %>

意见/职位/ index.js.erb的

 $('#placeholder').html("<%= j (render 'all_posts') %>"); 

正如你想从单一方法索引#home那样实现这一点。 然后你必须通过链接传递一些额外的信息

 
<%= render 'name_of_your_default_partial' , locals: {collection: @collection} %>

现在我们必须编辑我们的控制器。 在控制器顶部添加此行

 ALLOWED_REQUESTS = { p: 'Post' , s: 'Story' , b: 'Book' } 

将您的主页操作编辑为

 @request = params[:request].blank? ? 'Post' : ALLOWED_REQUEST[params[:request].to_sym] @collection = @request.constantize.all 

现在是时候渲染适当的部分。 如果你有不同的表格结构,并且你想要显示不同的html的不同字段,那么你可以创建三个不同的部分作为_book.html.erb,_story.html.erb,_post.html.erb,你可以像在家里一样调用它.js.erb文件

 $('[data-load-partial]').html('<%= j render partial: "#{@request.downcase}" , locals: { collection: @collection } %>'); 

如果你想对三种类型使用相同的部分,那么你可以这样做

 $('[data-load-partial]').html('<%= j render partial: "name_of_your_partial" , locals: { collection: @collection } %>');