Dru
Dru

Reputation: 9820

Updating Elements in Rails with Ajax

The app allows users to vote on embedded videos. When users click up and down arrows, the whole page refreshes to update points. I have been attempting to implement AJAX voting for months now. I would like the most straightforward solution you can offer, even if it isn't the most efficient. Any ideas?

My up and down actions from app/controllers/links_controller

  ....

  def up
    @link = Link.find(params[:id])
    @link.update_attribute :points, @link.points + 1
    redirect_to :back 
  end

  def down 
    @link = Link.find(params[:id])
    @link.update_attribute :points, @link.points - 1
    redirect_to :back 
  end 

  ....

A minimalist version of links_list, a partial from app/views/links/_links_list, which I render in other views using various sorting methods

  <% @links.each do |link| %>
        <div class="row">
            <div class="span2">
                <%= link_to (image_tag ("up.png")), up_link_url(link), :method => :put %> 
                <%= link.points %>
                <%= link_to (image_tag ("down.png")), down_link_url(link), :method => :put %>
            </div>
            <div class="span8">
                <%= link_to strip_tags(link.title), link %> 
            </div>
        </div>
  <% end %>

Thanks in advance for any feedback or suggestions!

Upvotes: 5

Views: 4011

Answers (1)

Veraticus
Veraticus

Reputation: 16084

Ajax is pretty easy to use in Rails 3.1. This post assumes you're using jQuery as your JavaScript driver; if you aren't, you'll need to install the jquery-rails gem, but even for an app in production adding a small gem shouldn't be a really big deal.

Your controller will end up looking like this:

....

def up
  @link = Link.find(params[:id])
  @link.update_attribute :points, @link.points + 1
  respond_to do |format|
    format.html {redirect_to :back}
    format.js
  end
end

def down 
  @link = Link.find(params[:id])
  @link.update_attribute :points, @link.points - 1
  respond_to do |format|
    format.html {redirect_to :back}
    format.js
  end
end 

....

The view change will be pretty small:

<% @links.each do |link| %>
  <div class="row">
    <div class="span2">
      <%= link_to (image_tag ("up.png")), up_link_url(link), :method => :put, :remote => true %> 
      <%= link.points %>
      <%= link_to (image_tag ("down.png")), down_link_url(link), :method => :put, :remote => true %>
     </div>
     <div class="span8">
       <%= link_to strip_tags(link.title), link %> 
     </div>
  </div>

And you'll need new files, up.js.erb and down.js.erb, in your app/views/links/ folder, which contains the JavaScript command to update your page:

$(".span2").html("This post has <%= @link.points %> points.")

If you decide to go with Prototype or something the code will look more or less the same; the only change will be the JavaScript you place in up.js.erb and down.js.erb, which should be Prototype-y instead of jQuery-y.

Upvotes: 10

Related Questions