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

时间:2016-08-10 13:49:58

标签: ruby-on-rails ruby ruby-on-rails-4

所以我有这样的布局:

家/ 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>

在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

在我的观看次数/帖子/ index.js.erb

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

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

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

_posts.html.erb views/posts_stories_html.erb中的views/stories

当我点击帖子按钮时,会发生视图,但是当我点击故事按钮时,什么都没有渲染?

3 个答案:

答案 0 :(得分:16)

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

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

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

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

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

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

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

因此,要发出AJAX请求,我们需要一个链接,点击后会发送XMLHttpRequest(异步请求),服务器应该回复JSONXML或者然后脚本应解析响应并更新DOMDocument Object Model)。在Vanilla JS(普通javascript)中发出AJAX请求很复杂,人们通常使用Jquery的{​​{1}}方法发出AJAX请求(代码行数较少)。有关详细信息,请参阅http://api.jquery.com/jquery.ajax/

但在ajax中,它更容易。我们可以使用railsUnobtrusive Javascript)发出AJAX请求。让我们看看它在行动。

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

例如以下erb

data-remote=true

生成html

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

确定。现在我们已经准备好发出<a data-remote="true" href="/books">All books</a> 个请求了。将代码修改为

AJAX

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

rake routes

注意:此处Prefix Verb URI Pattern Controller#Action posts GET /posts(.:format) posts#index stories GET /stories(.:format) stories#index books GET /books(.:format) books#index 对应于返回的格式,可以是formathtmljsxml

其中一个json中的posts_path指向url_helper,这意味着每当向posts#index应用程序中的服务器发出请求时,它首先到达路由器并且系统会调度到rails

中指定的相应controller操作

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

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

我将解释如何处理script的AJAX请求,并且您可以对其他控制器应用相同的想法。(BooksControllerposts)。

stories

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

实际上,index.js.erb推断要从controller名称呈现的模板。

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

创建部分is a partial for

app/views/books/_books.html.erb

现在创建<% @books.each do |book| %> <div class="book"> #Display the fields </div> <% end %> 并添加以下内容:

app/views/books/index.js.erb

此单行将部分$("#content").html("<%= j (render 'books') %>"); 呈现为_books.html.erb div。等待。它是如何工作的?让我们分成几块。

#content内的任何内容都是ruby代码。它的执行和值被替换为<%= %><%= %>模板化工具允许您在erb内编写ruby代码。那么,这是做什么的呢?

javascript

它将呈现<%= j (render 'books') %> ,从参数推断为books/_books.html.erb。它返回render生成的html。

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

解释_books.html.erb html的原因会使这个答案更长。我强烈建议您在this SO帖子中阅读kikito的答案(第3个答案)。

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

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

对其他控制器(NetworkPostsController)执行相同的操作。

希望这有帮助。

答案 1 :(得分:0)

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

这些动作必须响应js并渲染其js视图。

这将是这样的:

您的观点:

<div style="margin-top:50px;" class="wrapper">
  <div class="optionscontainer btn-group btn-group-justified">
    <%= link_to 'All Posts', posts_path, class: 'options btn btn-primary', method: :get, remote: true %>
  </div>
  <div id='placeholder'>
    <%= render 'all_posts' %>
  </div>
</div>

视图/帖/ index.js.erb的

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

答案 2 :(得分:-2)

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

<div style="margin-top:50px;" class="wrapper">
  <div class="optionscontainer btn-group btn-group-justified">
    <a style="background-color:#4183D7;" href="<%= path_to_index_home(request: :p) %>" class="options btn btn-primary" data-remote=true><i class="fa fa-book optionseach" aria-hidden="true"></i>All posts</a>
    <a style="background-color:#59ABE3;" href="<%= path_to_index_home(request: :s) %>" class="options btn btn-primary" data-remote=true><i class="fa fa-rss optionseach" aria-hidden="true"></i>all stories</a>
    <a style="background-color:#81CFE0;" href="<%= path_to_index_home(request: :b) %>" class="options btn btn-primary" data-remote=true><i class="fa fa-users optionseach" aria-hidden="true"></i>all books</a>
  </div>
  <div data-load-partial>
    <%= render 'name_of_your_default_partial' , locals: {collection: @collection} %>
  </div>
</div>

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

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 } %>');