Friday, August 19, 2016

Using jQuery Ajax in Rails Appliccations

Normally, we build a restful rails application when a ordering transaction system is needed. However, imaging a scenario such as a bicycle with three attributes:
  • model
  • size
  • color
The size and color options vary by model and they are not always the same combination across all models. For example, model A has size options of 700c X 48cm, 700c X 50cm and 700c X 52cm and color options of red, blue and black. Model B may have 700c X 48cm and 700c X 50cm and color options of green and orange. Therefore, when model changes during user operation, the size and color options must be changed accordingly.
That is a big design problem for a Rails application. Unless there is a a button for user to press and refresh the page while a model has been chosen, the Rails app has no idea when to refresh the page.
I use jQuery to solve this problem.
jQuery ajax can be used to listen the change of the model selection. When the model change happens, ajax calls the get_info function in orderdetails controller.
/view/orderdetails/new.html.erb
<script type="text/javascript">
$('#orderdetail_model_id').on('change', function() {
    $.ajax({
      url: '/get_info',
      type: 'GET',
      data: { model_id: this.value }
    })
  });
</script>  
The path is set in the routes.rb first.
get '/get_info', to: 'orderdetails#get_info', as: :get_info
Then ‘get_info’ function returns the instance variables needed for the page refresh.
controller orderdetails#get_info
def get_info
  @model  = Model.find(params[:model_id])
  @sizes  = @model.sizes
  @colors = @model.colors
  respond_to do |format|
    format.js
  end
end
Here is the magic: ‘get_info.js.erb’ replace the size and color select in their divs . The size and color options changes while model changes.
get_info.js.erb
$("#orderdetail_select_size_id").html("<%= escape_javascript(select("orderdetail", "size_id", @sizes.collect {|s| [s.name, s.id ] }, { include_blank: false })) %>");
$("#orderdetail_select_color_id").html("<%= escape_javascript(select("orderdetail", "color_id", @colors.collect {|c| [c.name, c.id ] }, { include_blank: false })) %>");
$("#orderdetail_text_field_price").html("<%= escape_javascript(text_field_tag("orderdetail", @model.price, style: "text-align: right", disabled: true )) %>");
TIP:
The code to be replaced need to be modified in the ‘get_info.js.erb’.
The ‘f.select’ causes error because ‘f’ is not defined in the replaced code portion.
f.select("size_id", Model.find_by_id(orderdetail.model_id).sizes.collect {|s| [ s.name, s.id ] }, { include_blank: false })
We have to replace it to the name of the select. By inspecting the generated html file, the name of the select is “orderdetail_select_size_id”. Using select_tag and name the variable as “orderdetail”, the problem solved and it works.
select("orderdetail", "size_id", @sizes.collect {|s| [s.name, s.id ] }, { include_blank: false }))"

No comments:

Post a Comment