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!
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
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:
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.
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:
At this point you can fire up a Rails server and the app will load up in your browser:
Point your browser to http://localhost:3000 and you should see this:
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:
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:
Okay, everything is in place. Now we’re ready to turn this into a mobile app!
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:
<body> <%= yield %> </body>
<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.
<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 %>
<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:
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!
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:
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>
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!
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.
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!