Kopty
Kopty

Reputation: 548

Use ajax to pre-load a page in a Rails app and then display it within the main layout

I have a simple application that is currently working, but I am trying to convert it to use ajax in order to improve the user experience so that full page reloads are not required every time a user clicks a link in the navigation. It uses a simple Header / Body / Footer approach with the nav bar included inside the header.

So currently, when I click on any of my nav items, it correctly changes the active-state CSS highlight properly, which I have done using Coffeescript.

As you will see in the code below, my 4th link in the navigation links to "new_movie_path". This page uses Nokogiri to crawl a web site (for example IMDB.com) and displays the current Box Office Top 10 movies, so it is something that can take a few moments to do and does not load instantly. This module individually is working just fine.

What I am trying to do is make it so that when I click on that link, it doesn't refresh the page, but instead, fetches the data using an ajax call and shows the result within the body of my current layout. I have added the remote: true element to the link but after much trial and error have failed to figure out the rest. Bonus: A spinner appears while the data is being loaded.

Snippets from my existing code:

/app/views/layout/application.erb.html

<body>
  <%= render 'shared/header' %>
  <div class="container first-contain" id="body-content">
    <%= yield %>
  </div>
</body>

/app/views/shared/_header.html.erb

<ul class="nav">          
  <li class="active"><%= link_to "Home", "#" %></li>
  <li><%= link_to "About", "#" %></li>
  <li><%= link_to "Contact", "#" %></li>
  <li><%= link_to "New Movies", new_movie_path, remote: true %></li>
</ul>

/app/assets/javascripts/navigation.js.coffee

$ ->
  changeTab = (e) ->
    e.preventDefault()
    $("ul.nav li.active").removeClass "active"
    $(@).addClass("active")
  $("ul.nav li").click changeTab

Any help in this matter is much appreciated.

Upvotes: 0

Views: 596

Answers (2)

abject_error
abject_error

Reputation: 2938

You need another file to handle the AJAX request. Suppose that movies link takes you to the 'show' action, then you would have a movies/show.js.erb view template file.

Let's say the action crawls IMDB and populates an array of names of movies in @movies

Your view file might then look like this:

<% 
  if @movies
    out = ''
    @movies.each do |m|
      out += m + '\n'
    end
%>
$("#body").html('<%= out %>');
<% end %>

This assumes you're using jquery ofcourse (and you should be). Essentially, you have to, one way or another, use javascript to replace the contents of your HTML body.

Upvotes: 1

jvnill
jvnill

Reputation: 29599

The ajax request should send you to MoviesController#new which is already working as you've said. You need to add a new view called new.js.erb under app/views/movies which will contain the javascript that you want to run after the request finishes ie

# movies_controller.rb
def new
  @movies = parse_movies_from_imdb
end

# new.js.erb
<% @movies.each do |movie| %>
  console.log(movie);
<% end %>

Upvotes: 0

Related Questions