To give the idea a thorough exploration, I built a small Rails 4.2 app called People. People1 looks a lot like the todo list apps used to test web frameworks except you manage people instead of todos.
It turns out it is easy. Here’s a gif showing the app in action. I wanted to see how well the approach allows me to:
- create, edit, delete, and show people
- show validations and flash messages
- edit a resource in place
Let’s walk through the process of writing the app.
Create the App
First, I create a new app called “people”. Once Rails does it’s thing, I use the
rails generators to scaffold a
I don’t need everything rails generates by default, so I delete
To make things look decent without too working hard (We’re prototyping here!), I
add gems Bootstrap and Font Awesome
to my gemfile. I also remove
gem turbolinks because I don’t really need it and I don’t want it
causing me any confusion.
bundle install installs my new gems and I’m almost done my setup. I just
need to setup Bootstrap and Font Awesome.
application.scss and write:
Finally, I add
root 'people#index' to
routes.rb, so the app has somewhere to
go when it’s opened.
Create the Responses
Now that I have the app setup, I can begin my experiment. I start by building
the index page because it’s the main page of the app. Just like the todo list
apps, I want a list of people. I want to use a form to add new people to my
list, so I create an instance of
I render the form on the index page(
index.html.erb) and display the list of people:
_form.html.erb, I set the form to submit using AJAX by giving the option
remote: true. This allows me to submit the form without leaving the page. To
handle this remote request, I need to modify
people_controller.rb to return
format.json. In case I want to render a flash message, I set
flash.now, which makes the message available in the current request.
I want to update the list of people and want the list to be sorted, so I write
@people = Person.all.order(first_name: :asc).
The form submission is received by the
create action, so I add
create.js.coffee and in it I write the changes I want to make to the page. I
add a presence validation to
person.rb ensure the person has a first name.
The form builder gives the form an id of
new_person and I use it to prepend
the message. The Ah ha! moment I had while implementing the error display, is
that errors are just like any other data and can be rendered in whatever way
makes sense for the app. In the traditional request oriented approach, I would
normally render the
new view with
@person which would cause the errors to be
shown. In this case, the form is already on the page, so all I need to do is add
error message html in my form partial, I could re-render the form with the
errors. I chose to extract the error html out into partial, so I can reuse it as
needed. If the submission is error free I remove the error html, in case it
exists, and render the list.
Edit in Place
I want to be able to edit the data I enter into the app. Everything up to this
point has been fairly straight forward. To create a new person, I fill out the
form and press “Add”. How do make it so I click the person’s name on the list
and the edit form opens? I didn’t want to add an edit link, so I dove into the
jquery_ujs to see if I could reuse it’s code to make a remote call
when I click the person’s name.
jquery_ujs works behind the scenes to make it possible to submit the
new form without changing pages. It watches
<a>s for the data
attributes added by the view helpers when
remote: true is passed as an option.
These attributes provide the information needed to make the remote request.
I found my answer starting on line 131 of jquery_ujs in
handleRemote is the
jquery_ujs class to make the ajax call when a remote link is clicked or
form is submitted and is exposed by the plugin.
The code above means that any element that’s not watched by the plugin with the
data-method, and optionally
data-params can be used to
make AJAX calls. All I need to do is add the attributes with the correct values
to the element and call
handleRemote when I want the request sent. With this
knowledge, I add click handler on the person’s name.
_person.html.erb renders each list element with those attributes. With
the click handler I make an AJAX call to the edit path of the person.
edit.js.coffee, I return a form (
_edit_form.html.erb) styled to fit in
the list element.
For those wanting a closer look, the code is available on GitHub.
Tips and Tricks
- Make use of the classes and ids generated by the helper methods and form builder
- Use jQuery’s
onmethod to attach event handlers to persistent elements in the DOM.
Your app is only as fast as the network
In most cases the network is fast. When it isn’t, you can use progress indicators to indicate the app is still alive.
Loss of network connection makes it impossible for the app to work
This is the same drawback as a “traditional” website. No internet means no pages are delivered, so it’s not really a problem unless you’re trying to create an offline app.