ely0qa
Last Updated: February 25, 2016
·
1.552K
· sebastialonso
9b0f7bbf22d65fa2bd23496973c0ba80

Simple Ajax calls in Rails

Let's suppose you have a basic menu like this one

Ugly view

And you want the Premium state (any boolean attribute) to change on click for a given local (any object).

A really neat way for doing these kind of things is through AJAX Calls, that is changing the state of the DOM tree without reloading the page.

Setting everything up

What I do is to write some specific routes for this, and I only want those routes to be accessible though AJAX and AJAX only. The following does the trick

#config/routes.rb
Rails.application.routes.draw do
  class OnlyAjaxRequest
     def matches?(request)
       request.xhr?
     end
  end
#rest of the routes
end

We'll come to this later.

Now see the view

#app/views/show.html.erb
  ...
<a href="" data-remote=true id="unique_id" class="premium-state"><%= local.premium %></a>
  ...

and notice the data-remote field, this is fundamental for what we want. It says to the controller that when we click this link, we don't want it to be sent to the regular HTML format procedure. Rather we want the JS one.

In the controller (mind this is just a quick way to write the controller method, but you should check for example, if the update_attributes is successful

#app/controllers/locals.rb
def set_premium
  local = Local.find params[:local_id]
  if local.premium #if local is premium, we set it to false
    local.udpdate_attributes(:premium => false)
    @message = "true"
  else
    #same thing for premium false
  end
  respond_to do |format|
     format.js
  end
end

See the format.js line there? It saying the controller: 'don't render the html response (the view), instead render the javascript response.

Now, when you respond with HTML you need to have a view in html format. Now you need one with js.erb extension.

#set_premium.js.erb
$("#unique_id").text("<%= j @message %>");

This code will be executed when you click the unique_id link in the view.

But wait...

We haven't even set the route for this action.

#config/routes.rb
resources :locals do
  post 'set_premium' => 'locals#set_premium', constraint: OnlyAjaxRequest.new  

There it is. The constraint part indicates that this call has to be made through AJAX.

How do I call this route

Did you notice the <a> element did not have an href field? I do that through Javascript

#app/assets/javascripts/locals.js.coffee
$(".premium-state").on "click", ->
  local_id = $(this).attr('id');
  $.ajax {
    url: ROUTE_TO_YOUR_ACTION
    type: 'post'
    dataType: 'script'
    success: () ->
  }

where ROUTE_TO_YOUR_ACTION is the path that the rake routes command pukes for that specific controller action.
A couple of remarks:

  • the dataType field of the AJAX call is 'script'. Think of that as the AJAX requesting a script file and executing it.
  • the sucess function does not have instructions. The instructions go in the Javascript view for the method you requested!
  • the type field has to be consisting with the naming of the custom route.

aaaaaaand we're done.

And I think that's it. Your AJAX button should be working by now.

Feel free to point out any inconsistency in the article, so I can fix it/explain it.

1 Response
Add your response

20931
9a0f5684ee6ac5dbf66551da5f7a6610 normal

hello bro. I'm getting error. it says

500 (Internal Server Error)

over 1 year ago ·