Getting Started with jQuery Mobile & Rails 3

The very promising jQuery Mobile project is now in its first Alpha release! What better time to give it a spin with our (err… my) favorite web framework?!

You should read jQuery Mobile’s official introduction section to familiarize yourself with its principles, but in a few words: you include it on the page, format your markup to conform to its requirements and reap the benefits. Yay, let’s write a (very contrived) CRUD application with Rails 3 and jQuery Mobile!

Setup

Our application will allow us to create, read, update and delete blog posts (remember when I said it was contrived? Uhm..yah) from mobile devices. If you don’t have Rails 3 installed yet, you can get it via RubyGems:

gem install rails

Use the rails command line tool to generate a new application. We’ll call it jqmoblog.

rails new jqmoblog
# ... a bunch of files are created
cd jqmoblog

As of Rails 3.0.1 you cannot specify jQuery as the JavaScript tool of choice when you generate a Rails application, but we can easily swap it in by using the handy, dandy jquery-rails gem. Edit the Gemfile in the project’s root directory and add a dependency on the gem. Once finished your Gemfile will look something like this:

source 'http://rubygems.org'

gem 'rails', '3.0.1'
gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'jquery-rails'

Install the required gems using the bundle command line tool:

bundle install

Now we’ll use the Rails generator added by the jquery-rails gem to get all the jQuery files we need:

rails generate jquery:install

When prompted, allow it to overwrite rails.js.

We’re almost ready. The application skeleton is in place and jQuery has replaced the Rails default JavaScript libraries, but we’re missing the basic model, controller, and views for our application.

Thankfully, Rails has a generator which will create these files for us and its called the scaffold generator. We’ll keep the blog posts in our app super-simple since we’re really just using them to learn about jQuery Mobile. Each post will have a title and a body. Generate the scaffold for a Post resource like this:

rails generate scaffold Post title:string body:text

This command will provide a list of files and directories it created. There should be a model (app/models/post.rb), a controller (app/controller/posts_controller.rb), and a directory of views (app/views/posts) for our Post resource.

Run the database migration that was created from the scaffold command so our database has a posts table with the required columns for storing our posts:

rake db:migrate

At this point you can fire up a Rails server and the app will load up in your browser:

rails server

Point your browser to http://localhost:3000 and you should see this:

default

Hmm, before we get to mobilizing this application, let’s make the root url load the list of our posts instead of the default Rails index file:

rm public/index.html

Edit the config/routes.rb and set the root route like so:

Jqmoblog::Application.routes.draw do
  resources :posts
  root :to => "posts#index"
end

Now load up http://localhost:3000 again and you should see the empty list of posts.

We still need to get the jQuery Mobile files on the page. Lets use the ones hosted on jquery.com. Add them to the application’s layout file so they’ll be on every page that gets served. In app/views/layouts/application.html.erb, edit the head section to look like this:

<head>
  <title>Jqmoblog</title>
  <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.css" />
  <%= javascript_include_tag :defaults %>
  <script src="http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.min.js"></script>
  <%= csrf_meta_tag %>
</head>

Okay, everything is in place. Now we’re ready to turn this into a mobile app!

Getting Started

Before we flesh out our mobile CRUD actions, let’s get the posts index looking decent in mobile browsers. jQuery Mobile relies directly on the page’s markup to work its magic, so to invoke it we just need to change our views to conform to its conventions.

Each “page” in a jQuery Mobile application needs to be wrapped in a div with a data-role attribute of page. I put “page” in quotes because there can actually be many of them on a single webpage loaded from the server. In our app we’ll be loading each “page” from Rails, so we should just add this to our layout file which will wrap each of our individual views:

Before

<body>
  <%= yield %>
</body>

After

<body>
  <div data-role="page">
    <%= yield %>
  </div>
</body>

Next edit the post’s index (index.html.erb) and change the markup to create a header and a content section which lists all the posts in the database.

Before

<h1>Listing posts</h1>

<table>
  <tr>
    <th>Title</th>
    <th>Body</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @posts.each do |post| %>
  <tr>
    <td><%= post.title %></td>
    <td><%= post.body %></td>
    <td><%= link_to 'Show', post %></td>
    <td><%= link_to 'Edit', edit_post_path(post) %></td>
    <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New Post', new_post_path %>

After

<div data-role="header">
  <h1>Listing posts</h1>
</div>

<div data-role="content">
  <ul data-role="listview">
    <% @posts.each do |post| %>
    <li>
      <%= link_to post.title, post %>
      <%= link_to 'edit post', edit_post_path(post), "data-icon" => "gear" %>
    </li>
    <% end %>
  </ul>
</div>

Load up the page and it should look like this:

base

Two things to note here. First, we are once again using the data-role attribute to create the header and the styled list. This is a major theme of jQuery Mobile (as of the Alpha, I’m told they *might* be switching to class names instead of data- attributes). Second, each list item has two links, and jQuery Mobile automatically knows that this means we want to use a split button list. Pretty cool, huh?

Let’s add a button which will take us to a page where we can create new posts. Add this line to the end of the header div:

<%= link_to 'Add', new_post_path, "data-icon" => "plus", "class" => "ui-btn-right" %>

Again, jQuery Mobile “just knows” that this should be a button in our header and we pass it a class and a data-icon attribute to tell it where to place it and which icon to use. We now have a button in the header which links to the new post path!

base-add

Create

We’re gonna need to create posts so we can read, update and delete them, so lets handle creation first. The “Add” button on the posts index links to the new.html.erb view. It works as is and looks okay too. We’ll just tweak the markup to make it fit into the jQuery Mobile styles:

<div data-role="header">
  <h1>New Post</h1>
</div>

<div data-role="content">
  <%= render 'form' %>
</div>

We can now add new posts using the mobile interface! Go ahead and create a few so the posts index shows a list with links to edit each post:

base-posts

Read

People will read posts from their show.html.erb view. Again, no change to the underlying controller or model code needs to happen. Just update the view file to look like this:

<div data-role="header">
  <h1><%= @post.title %></h1>
  <%= link_to 'Home', posts_url, "class" => "ui-btn-right" %>
</div>

<div data-role="content">
  <%= @post.body %>
</div>

post-show

Update

When we set up the posts index we added links to the edit.html.erb view using the gear icon on the right side of the split list. Now we just need to change the markup on that view to conform to jQuery Mobile’s requirements. Have you sniffed out a pattern to this development process yet?

<div data-role="header">
  <h1>Editing Post</h1>
</div>

<div data-role="content">
  <%= render 'form' %>
</div>

Again, it just works as expected and it will look great on many mobile devices. On to the final action, delete!

Delete

To facilitate deleting a post we just have to modify the delete links created by Rails’ scaffold generator to fit the rest of the mobile site. I think the edit page is a good place to add a delete link, so lets add a button to the header of edit.html.erb:

<%= link_to 'Delete', @post, :method => :delete, "data-icon" => "delete", "class" => "ui-btn-right" %>

The edit view is now complete, and it lets us update and delete our post.

post-edit

Closing Up

If you’ve made it this far, you’ve probably realized that working with jQuery Mobile is pretty painless and it fits in with Rails quite well. There are a bunch of other things that jQuery Mobile can do, but this should hopefully whet your appetite. Remember, the framework is still in the Alpha stage so things can and probably will change.

I encourage you to read more about the project and get involved at an early stage so we can all benefit from a strong community!

***Download the source code for the application built in this post***

Jerod Santo is an Editor at Fuel Your Coding and a contract software developer at RSDi where he works daily with Ruby, JavaScript, and related technologies. He loves shiny toys, powerful tools, and open-source software. Learn more about Jerod by visiting his homepage or following him on Twitter.

 

If you liked this article, please help spread the news on the following sites:

  • Bump It
  • Blend It
  • Bookmark on Delicious
  • Stumble It
  • Float This
  • Reddit This
  • Share on FriendFeed
  • Clip to Evernote