根据点击的按钮渲染三个不同的部分
所以我有这样的布局:
家用/ index.html.erb:
在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.erb
在views/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
因为它等待服务器的响应。 单击链接时会发生相同的过程。 它会向服务器创建一个新请求。
服务器的响应可以是HTML
, JSON
, XML
等。您可能已经注意到, synchronous
通信并不是我们一直想要的。
如果我们发出新的synchronous
请求,浏览器会再次获取HTML
, CSS
和JS
以及image
文件(不要进入缓存)。 我们不希望为每个请求更新整个页面。
通常,只有部分页面在请求后更新,并提供良好的用户体验。
这是Javascript擅长的地方。 它可以异步地向服务器发出请求(网页不会重新加载),还可以使用名为AJAX
( 异步Javascript XML )的内容更新页面的某些部分。
典型的AJAX请求是这样的。 您向服务器发出请求,但这次是异步的,服务器用XML
而不是HTML
响应, Javascript
解析XML
文档更新页面的一部分。 尽管它现在被称为AJAX,但是现在,JSON用于跨服务交换信息。
因此,要发出AJAX请求,我们需要一个链接,当单击时发送XMLHttpRequest
(异步请求),服务器应该使用JSON
或XML
响应,然后脚本应该解析响应并更新DOM
( 文档对象模型 )。 在Vanilla JS
(普通javascript)中发出AJAX请求很复杂,人们通常使用Jquery
的ajax
方法来发出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
请求。 将您的代码修改为
我假设你有控制器,模型和视图设置。 同时在终端中执行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
对应于返回的格式,可以是html
, js
, xml
或json
。
在其中一个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请求,你可以将相同的想法应用于其他控制器。( posts
和stories
)。
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.erb
或index.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的工作原理。
对其他控制器( PostsController
和StoriesController
)执行相同的StoriesController
。
希望这可以帮助。
链接必须设置为remote: true
,它们必须指向不同的操作(或相同但接收不同的参数)。
这些动作必须响应js并呈现其js视图。
它会是这样的:
你的观点:
<%= 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 } %>');