13.3. Example

The easiest way of explaining how you go about programming with JavaScript and the asset pipeline in a Rails project is by using a little example. As always, the main focus is not on creating an amazingly meaningful application. ;-)

Changing Form Depending on Input

Let's build a room reservation where you can book a single or double room and then have to enter either one or two guest names in the same form. The basic structure:
$ rails new hotel
  [...]
$ cd hotel 
$ rails generate scaffold reservation start:date end:date room_type:string guest_name1 guest_name2
  [...]
$ rake db:migrate
  [...]
$ rails server
  [...]
With this setup we will get a very spartanic http://0.0.0.0:3000/reservations/new
The Basic Form
That is not userfriendly. The aim is to display the following page when you go to http://0.0.0.0:3000/reservations/new:
Form with a single room
As soon as the user selects a double room instead of a single, we want a second name field to appear:
Form with a double room
So I am changing two things in the app/views/reservations/_form.html.erb:
  • Set the room_type via a dropdown box.
    <%= f.select :room_type, options_for_select(['single room', 'double room']) %>
  • In the div element around the second name, I set an ID 'second_name'.
    <div class="field" id='second_name'>
Here is the whole new code for app/views/reservations/_form.html.erb
<%= form_for(@reservation) do |f| %>
  <% if @reservation.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@reservation.errors.count, "error") %> prohibited this reservation from being saved:</h2>

      <ul>
      <% @reservation.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :start %><br>
    <%= f.date_select :start %>
  </div>
  <div class="field">
    <%= f.label :end %><br>
    <%= f.date_select :end %>
  </div>
  <div class="field">
    <%= f.label :room_type %><br>
    <%= f.select :room_type, options_for_select(['single room', 'double room']) %>
  </div>
  <div class="field">
    <%= f.label :guest_name1 %><br>
    <%= f.text_field :guest_name1 %>
  </div>
  <div class="field" id='second_name'>
    <%= f.label :guest_name2 %><br>
    <%= f.text_field :guest_name2 %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
In the file app/assets/javascripts/reservations.js.coffee I define the CoffeeScript code that toggles the element with the ID second_name between visible (show) or invisible (hide) depending on the content of reservation_room_type:
ready = ->
  $('#second_name').hide()
  $('#reservation_room_type').change ->
    room_type = $('#reservation_room_type :selected').text()
    if room_type == 'single room'
      $('#second_name').hide()
    else
      $('#second_name').show()

$(document).ready(ready)
$(document).on('page:load', ready)

Buy the new Rails 5.1 version of this book.

In reality, you would surely integrate the guest names in a 1:n has_many association, but in this example we just want to demonstrate how you can change the content of a form via JavaScript.

Thank you for your support and the visibility by linking to this website on Twitter and Facebook. That helps a lot!