2016-08-10 48 views
3

所以我有这样的布局:渲染视按钮三个不同的谐音点击

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

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

在我的意见/故事/ index.js.erb的

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

我也有_posts.html.erb in views/posts and _stories_html.erb in views/stories

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

+1

你怎么想使它们?作为一个AJAX请求?你知道如何在控制器上创建一个动作吗? – yogodoshi

+0

我是新来的rails和web开发,如果AJAX是最好的方式,请做一个例子 –

回答

12

好了,进入了解决方案之前,让了解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请求时,浏览器获取HTMLCSSJSimage文件一遍(让我们不要进入高速缓存)。我们不想为每个请求更新整个页面。

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

这是Javascript擅长的地方。它有权异步向服务器发出请求(网页不重新加载),并使用名为AJAXAsynchronous Javascript XML)的东西更新页面的某些部分。

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

所以,做一个AJAX请求,我们需要点击它时,发送XMLHttpRequest(异步请求)和服务器端应JSONXML或响应,然后脚本应该解析响应和更新的链接DOMDocument Object Model )。在Vanilla JS(普通javascript)中发出AJAX请求很复杂,人们通常使用Jqueryajax方法来发出AJAX请求(少量代码行)。有关更多信息,请参阅http://api.jquery.com/jquery.ajax/

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

要使链接发送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">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 

注:format这里对应于可htmljsxmljson返回的格式。

posts_path在指向posts#index,每当请求以rails应用向服务器发出意味着url_helper之一,它首先到达路由器和被分派到在routes.rb

指定在对应controller动作在这种情况下,如果我们向http://localhost:3000/books发出请求,则将请求发送到books#index操作。在操作中,您可以从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 views/books/index.html.erb 
     format.js #looks for views/books/index.js.erb 
    end 

    end 

    #other actions 
end 

所有我们在这里所做的是告诉控制器来呈现index.js.erb如果一个JS响应客户端的请求或HTML响应的情况下渲染index.html.erb。当我们没有指定要呈现的文件时,rails如何知道如何渲染index.html.erbindex.js.erb?多数民众赞成什么铁轨流行for.Rails如下Convention Over Configuration

实际上,controller推断模板从action名称渲染。

下一步是利用@books来更新#content div。在添加代码来呈现所有图书之前,我们需要一个模板来呈现对吗?这就是部分进来。部分是可重复使用的书籍。

创建一个局部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#content格。等待。它是如何工作的?让它分解成碎片。

<%= %>里面的东西都是红宝石代码。它的执行和值取代<%= %>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线索中阅读kikito的回答(第3个)。

所以,我们从部分经过HTML作为字符串(注意周围<%= %>引号),这是该#content DIV中添加html方法。而已!

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

对其他控制器(PostsControllerStoriesController)做相同的操作。

希望这会有所帮助。

+0

当我遇到一个小问题,我有书,帖子等的意见,但这些按钮在索引#主页并使用不同的控制器称为索引和方法主页。我更新了我的问题。 –

+0

@GurmukhSingh我不理解你。索引#home视图中有三个链接,每个链接向不同的控制器发送请求。在我的回答中,您可以找到指向'stories_path','books_path'和'posts_path'的链接。在我的回答中,我写了'books_controller'的步骤,以便'books_path'的链接呈现'js'响应。您可以对其他控制器重复相同的步骤(每个数据不同)。如果那不是你想要的,请评论所需的行为。 –

+0

所以基本上我试图在一个单独的视图呈现视图。邮政和书籍和独立的脚手架,他们有自己的看法。我在另一个名为index的控制器中工作,所以即时将上述逻辑应用于索引控制器,在那里为索引app/views/index/home.js.erb创建.js文件,然后放置$(“#content”) .html(“<%= j(render'books')%>”); (“#content”)。html(“<%= j(render'posts')%>”);它在同一个home.js.erb中。我希望这使场景:?这然后不起作用? –

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

正如你想从单一方法索引#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 } %>');