根据单击的按钮渲染三个不同的部分 [英] Render three different partials depending on button clicked

查看:40
本文介绍了根据单击的按钮渲染三个不同的部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有这样的布局:

home/index.html.erb:

<%= 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-book optionseach" aria-hidden="true"></i>所有故事<%结束%>

<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.erbviews/stories代码>

当我点击帖子按钮时会呈现视图,但当我点击故事按钮时什么都没有呈现?

解决方案

好的,在进入解决方案之前,让我们了解请求-响应循环.

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

来自服务器的响应可以是 HTMLJSONXML 等.您可能已经注意到,synchronous 交流不是我们一直想要的.

如果我们发出一个新的同步请求,浏览器会获取HTMLCSSJS>image 文件一遍一遍(让我们不要进入缓存).我们不想为每个请求更新整个页面.

通常,只有部分页面会在收到请求后更新,从而提供良好的用户体验.

这是 Javascript 擅长的地方.它有能力异步地向服务器发出请求(网页不会重新加载),还可以使用称为 AJAX(异步 Javascript XML).

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

因此,要发出 AJAX 请求,我们需要一个链接,点击该链接时会发送 XMLHttpRequest(异步请求),服务器应以 JSON 响应XML 或者脚本应该解析响应并更新 DOM(文档对象模型).在 Vanilla JS(普通 javascript)中发出 AJAX 请求很复杂,人们通常使用 Jqueryajax 方法发出 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这里对应的是返回的格式,可以是htmljsxml或<代码>json.

posts_path 在指向 posts#indexurl_helper 之一中,这意味着每当在 中向服务器发出请求>rails 应用程序,它首先到达路由器并被分派到 routes.rb

中指定的相应 controller 动作

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

因为我们对 AJAX 感兴趣并且我们已经指定了 remote:true,所以 Rails 会期望一个 JS 响应返回给客户端(即一个 负责动态渲染内容的脚本).

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

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.erbindex.js.erb ?这就是 rails 受欢迎的原因.Rails 遵循约定优于配置.

实际上,controlleraction 名称推断要呈现的模板.

下一步是利用@books 更新#content div.在添加渲染所有书籍的代码之前,我们需要一个模板来渲染对吗?这就是partials 的用武之地.partial 是一个可重用的view',而rails 中的partial 以'_' 为前缀.例如:_books.html.erbbooks`的部分.

创建部分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 的工作原理.

对其他控制器(PostsControllerStoriesController)执行相同操作.

希望这会有所帮助.

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: truein the link_to helper. This adds a data-remote=truein 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 forbooks`.

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屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆