根据单击的按钮渲染三个不同的部分 [英] Render three different partials depending on button clicked
问题描述
所以我有这样的布局:
home/index.html.erb:
<div id="content" class="">
在 posts_controller.rb 中
我有:
def 索引@posts = Post.allresponse_to do |格式|format.html #looks for views/books/index.html.erbformat.js #查找视图/书籍/index.js.erb结尾结尾
在 stories_controller.rb 中
我有:
def 索引@stories = Story.allresponse_to do |格式|format.html #looks for views/books/index.html.erbformat.js #查找视图/书籍/index.js.erb结尾结尾
在我的意见/帖子/index.js.erb
$("#content").html("<%= j (render 'posts') %>");
在我的观点/故事/index.js.erb
$("#content").html("<%= j (render 'stories') %>");
而且我在 views/posts
和 _stories_html.erb
中有 _posts.html.erb
在 views/stories
代码>
当我点击帖子按钮时会呈现视图,但当我点击故事按钮时什么都没有呈现?
好的,在进入解决方案之前,让我们了解请求-响应
循环.
当您搜索 http://stackoverflow.com 时,结果是您从 客户端 发送请求code>(您的浏览器)到 StackOverflow(SO)
server
.客户端和服务器通过 HTTP
协议进行通信,如果用户请求服务器知道的内容,它会提供(发送)响应(html、css、js 文件).浏览器知道如何显示从服务器接收到的 html 内容.每个浏览器都有自己的样式表(user-agent-stylesheet
),它还应用从服务器发回的 html 页面中链接的 css 文件中的样式.请注意,这一切都是同步发生的,当 server
正在处理客户端的请求时,浏览器选项卡处于 inactive
以等待服务器的响应.单击链接时会发生相同的过程.它向服务器创建一个新请求.
来自服务器的响应可以是 HTML
、JSON
、XML
等.您可能已经注意到,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 请求,您需要在 link_to
帮助器中设置 remote: true
.这会在生成的 HTML 中添加 data-remote=true
.
例如下面的erb
<%= link_to "All books", books_path, remote: true %>
生成html
<a data-remote="true" href="/books">所有书籍</a>
好的.现在我们都准备好发出一个 AJAX
请求.将您的代码修改为
<div class="optionscontainer btn-group btn-group-justified"><%= link_to posts_path, class:"options btn btn-primary", remote: true do %><i class="fa fa-book optionseach" aria-hidden="true"></i>所有帖子<%结束%><%= link_to stories_path, class:"options btn btn-primary", remote: true do %><i class="fa fa-rss optionseach" aria-hidden="true"></i>所有故事<%结束%><%= link_to books_path, class:"options btn btn-primary", remote: true do %><i class="fa fa-users optionseach" aria-hidden="true"></i>所有书籍<%结束%><div id="内容"><!-- 内容在这里-->
我假设您已经设置了控制器、模型和视图.还可以在终端中执行 rake routes
以查看应用程序的现有路由.您应该看到以下内容(顺序不重要)
前缀动词URI模式控制器#Action帖子 GET/posts(.:format) 帖子#index故事获取/故事(.:格式)故事#index书籍 GET/books(.:format) books#index
注意:format
这里对应的是返回的格式,可以是html
、js
、xml
或<代码>json.
posts_path
在指向 posts#index
的 url_helper
之一中,这意味着每当在 中向服务器发出请求>rails
应用程序,它首先到达路由器并被分派到 routes.rb
controller
动作在这种情况下,如果我们向 http://localhost:3000/books
发出请求,该请求将发送到 books#index 操作.在操作中,您可以从 database
获取数据并将响应发送到客户端.
因为我们对 AJAX 感兴趣并且我们已经指定了 remote:true
,所以 Rails 会期望一个 JS
响应返回给客户端(即一个 负责动态渲染内容的脚本
).
我将解释如何处理 BooksController
的 AJAX 请求,您可以将相同的想法应用于其他控制器.(posts
和 stories
>).
class BooksController <应用控制器定义索引@books = Book.allresponse_to do |格式|format.html #looks for views/books/index.html.erbformat.js #查找视图/书籍/index.js.erb结尾结尾#其他行为结尾
我们在这里所做的只是告诉控制器在客户端请求 JS 响应时渲染 index.js.erb
或渲染 index.html.erb
在 HTML 响应的情况下.当我们没有指定要渲染的文件时,rails 如何知道渲染 index.html.erb
或 index.js.erb
?这就是 rails 受欢迎的原因.Rails 遵循约定优于配置.
实际上,controller
从 action
名称推断要呈现的模板.
下一步是利用@books
更新#content
div.在添加渲染所有书籍的代码之前,我们需要一个模板来渲染对吗?这就是partials 的用武之地.partial 是一个可重用的view',而rails 中的partial 以'_' 为前缀.例如:
_books.html.erb是
books`的部分.
创建部分app/views/books/_books.html.erb
<% @books.each do |book|%><div class="book">#显示字段
<%结束%>
现在创建 app/views/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 的原因将使这个答案更长.我强烈建议您在 this SO 线程.
因此,我们将部分中的 html 作为字符串(注意 <%= %>
周围的引号)传递给 html
方法,该方法添加到#content
div.就是这样!
我建议您检查服务器日志并浏览开发者工具中的 Network
选项卡,以深入了解 AJAX 的工作原理.
对其他控制器(PostsController
和 StoriesController
)执行相同操作.
希望这会有所帮助.
So I have a layout like this:
home/index.html.erb:
<div class="optionscontainer btn-group btn-group-justified">
<%= link_to posts_path, class:"options btn btn-primary", remote: true do %>
<i class="fa fa-book optionseach" aria-hidden="true"></i>All posts
<% end %>
<%= link_to stories_path, class:"options btn btn-primary", remote: true do %>
<i class="fa fa-book optionseach" aria-hidden="true"></i>All stories
<% end %>
</div>
<div id="content" class="">
</div>
In posts_controller.rb
I have:
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
In stories_controller.rb
I have:
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
In my views/posts/index.js.erb
$("#content").html("<%= j (render 'posts') %>");
In my views/stories/index.js.erb
$("#content").html("<%= j (render 'stories') %>");
And I also have _posts.html.erb
in views/posts
and _stories_html.erb
in views/stories
What happens is when i click on the posts button i renders the view but when i click on the stories button nothing renders?
Ok, before getting into the solution, lets understand the request-response
cycle.
When you search for http://stackoverflow.com, what happens is you're sending a request from the client
(your browser) to the StackOverflow(SO) server
. The client and server communicate through HTTP
protocol and if the user's requesting for something that the server knows, it serves(sends) the response(html, css, js files). The browser knows how to display the html content received from the server. Every browser has its own stylesheet(user-agent-stylesheet
) and it also applies the styles in the css files linked in the html page sent back from the server. Note that this all happens synchronously and while the server
is processing the client's request, the browser tab is inactive
as its waiting for the server's response. The same process happens when you click on a link. It creates a new request to the server.
The response from the server can be HTML
, JSON
, XML
etc. As you might have noticed, the synchronous
communication is not something we always want.
If we make a new synchronous
request, the browser fetches HTML
, CSS
and JS
and image
files all over again(lets not get into caching). And we don't want to update the whole page for every request.
Often, only parts of the page are updated after a request and it provides a good user experience.
This is where Javascript is good at. It has the power to make requests to the server asynchronously(the web page doesn't reload) and also update parts of the page using something called AJAX
(Asynchronous Javascript XML).
A typical AJAX request goes like this. You make a request to the server but this time asynchronously and the server responds with XML
rather than HTML
and Javascript
parses the XML
document updates the part of the page. Eventhough its called AJAX, now-a-days, JSON is used for exchanging information across services.
So, to make a AJAX request, we need a link which when clicked sends a XMLHttpRequest
(asynchronous request) and the server should respond with JSON
or XML
or and then the script should parse the response and update the DOM
(Document Object Model). Making an AJAX request in Vanilla JS
(plain javascript) is complex and people normally use Jquery
's ajax
method to issue an AJAX request(less lines of code). See http://api.jquery.com/jquery.ajax/ for more information.
But in rails
, its even easier. We can make an AJAX request using UJS
(Unobtrusive Javascript). Lets see it in action.
To make a link send an AJAX request, you need to set remote: true
in the link_to
helper. This adds a data-remote=true
in the generated HTML.
For example the following erb
<%= link_to "All books", books_path, remote: true %>
generates the html
<a data-remote="true" href="/books">All books</a>
Ok. Now we're all set to make an AJAX
request. Modify your code as
<div style="margin-top:50px;" class="wrapper">
<div class="optionscontainer btn-group btn-group-justified">
<%= link_to posts_path, class:"options btn btn-primary", remote: true do %>
<i class="fa fa-book optionseach" aria-hidden="true"></i>All posts
<% end %>
<%= link_to stories_path, class:"options btn btn-primary", remote: true do %>
<i class="fa fa-rss optionseach" aria-hidden="true"></i>All stories
<% end %>
<%= link_to books_path, class:"options btn btn-primary", remote: true do %>
<i class="fa fa-users optionseach" aria-hidden="true"></i>All books
<% end %>
</div>
<div id="content">
<!-- The content goes here -->
</div>
I assume you have the controllers, models and views setup. Also Execute rake routes
in the terminal to see the existing routes of your application. You should see the following(Order isn't important)
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
stories GET /stories(.:format) stories#index
books GET /books(.:format) books#index
Note: format
here corresponds to the returned format which can be html
, js
, xml
or json
.
posts_path
in one of the url_helper
which points to posts#index
, meaning whenever a request is made to the server in a rails
application, it first reaches the router and is dispatched to the corresponding controller
action specified in routes.rb
In this case, if we make a request to http://localhost:3000/books
, the request is sent to the books#index action. In the action, you can fetch the data from the database
and send the response to the client.
Since we are interested in AJAX and we have specified remote:true
, rails will expect a JS
response to be returned to the client(ie. a script
which is responsible for rendering content dynamically).
I will explain how to deal with the AJAX request for BooksController
and you can apply the same idea for other controllers.(posts
and stories
).
class BooksController < ApplicationController
def index
@books = Book.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
#other actions
end
All we're doing here is telling the controller to render index.js.erb
if the client requests for a JS response or to render index.html.erb
in case of HTML response. How does rails knows to render index.html.erb
or index.js.erb
when we didn't specify the file to render? Thats what rails is popular for.Rails follows Convention Over Configuration.
Actually, the controller
infers the template to render from the action
name.
The next step is to make use of @books
to update the #content
div. Before adding the code to render all the books, we need a template to render right? Thats where partials come in. A partial is a reusable view' and a partial in rails is prefixed with '_'. For example:
_books.html.erbis a partial for
books`.
Create a partial app/views/books/_books.html.erb
<% @books.each do |book| %>
<div class="book">
#Display the fields
</div>
<% end %>
Now create app/views/books/index.js.erb
and add the following:
$("#content").html("<%= j (render 'books') %>");
This one-liner will render the partial _books.html.erb
into the #content
div. Wait. How does it work? Lets break it into pieces.
Anything inside <%= %>
is ruby code. Its executed and the value is replaced in place of <%= %>
. The erb
templating engline allows you to write ruby
code inside javascript
. So, what does this do?
<%= j (render 'books') %>
It will render the books/_books.html.erb
, inferred from the parameter to render
. It returns the html generated by _books.html.erb
.
What does j
do? Its actually an alias of escape_javascript
method. It is used to escape the content returned from the partial _books.html.erb
.
Explaining the reason for escaping
html will make this answer even longer. I strongly recommend you to read kikito's answer(the 3rd one) in this SO thread.
So, we are passing html from the partial as a string(note the quotes around <%= %>
) to html
method which is added inside the #content
div. Thats it!
I recommend you to inspect the server logs and explore the Network
tab in Developer tools to get a deep understanding of how AJAX works.
Do the same for the other controllers(PostsController
and StoriesController
).
Hope this helps.
这篇关于根据单击的按钮渲染三个不同的部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!