Wednesday, June 22, 2011

Rails: Calling Controller Action using onclick and Ajax (remote_function)

Say you want to call the update_reasons action in the reports controller in response to an onclick on a checkbox.

First, of course, you need the route in config/routes.rb



match "/reports/update_reasons" => "reports#update_reasons"



And, of course, the action...I just echo relevant arguments in this version.

Note, I render "nothing" because operation does not result in any view change beyond status change of checkbox which is managed by browser.


def update_reasons
  checked = params[:checked]
  params.each do |key, value|
    if /reasons_(\d+)/.match(value) != nil
      logger.debug("update reason #{$1} to #{checked}")
    end
  end
  respond_to do |format|
    format.js { render  :nothing => true }
  end
end


Using the check_box_tag, you will include on :onclick parameter. The value of :onclick is javascript. The "best" way to generate that javascript is using remote_function helper. I use the :with parameter to send request parameters

with the Ajax call. Notice in ruby code above reference to parameter names appearing in value of :with string in view code.



Here is my view code:



<% reasons.each do |infraction| %>
    <% rf =  remote_function(
       :url => { :controller => 'reports', 
               :action => :update_reasons },
       :with => '\'reason=\'+ this.id + \'&checked=\' + this.checked')  %>
    <%= check_box_tag "reasons[#{infraction.id}]", 
      infraction.description,
      false ,
      :onclick => "#{rf}",
      :class=>:"iToggle", :title=>"YES|NO" %>
    <%= infraction.description %>  
  <% end %>



If I expect some server-side generated change to view, I could include an :update argument to remote_function. This parameter names a div into rendered output is placed.

I admit I took a lazy approach by placing value of remote_function to a local variable. After much hair-pulling,I gave on trying to get quotes right with remote_function as direct value of :onclick parameter.

Monday, June 20, 2011

Contact Reasons Associated with a Report

I have added a method to RelationshipToReport model that returns a list of only those 'relationships' that apply to a given report type. The method name is for.

Here is an example usage:

infractions = RelationshipToReport.for(report)
infractions.each do |infraction|
...
end