Hoang Pham

iOS, Rails developer

Nov 23

My 2 days at Slush conference in Helsinki, Finland

It happened to me to be in Turku, Finland during the time of the conference, I arrived in Turku a week before to visit my sister and to sign up some documents with the bank as I opened my company called Cosmo Studios Oy here with her to focus on iOS development. I heard of the conference through Facebook by the guys at BoostTurku, “Slush is the largest tech, design & startup conference covering Northern Europe and Russia”, as they advertised on their website, I found it to be a perfect chance to extend my stay in Finland, so I decided to delay the return ticket to Milan to two days after the conference. After attending the conference, I can say that I did not regret about my decision.

————Follow me on Twitter: @pnhoang —————-

I registered through their website in a lightweight track as a startup, with hope that they will accept my application and let me have the chance to demo my application FMFinder during the event, but that was not the case. There were about 500 startups all over Europe registered to their website, and there’re only 100 slots for pitching. I got accepted as a startup but without the chance to pitch, I was a little bit disappointed at first, but I decided to go to the conference anyway. I bought the train ticket through vr.fi website and took the early train from Turku to Helsinki, as I want to save, I chose a Hostel close to the station that costs the least, it was ok for me by the way, the Hostel Erottajanpuisto has affordable price, and I had chance to talk to a bunch of people the night I stay there. Arrived in Helsinki station, I walked to the hostel which took me about 20 minutes, not so bad, exercising in the morning, dropped my luggage inside, and headed to the bus station close to the hostel. The bus 20 took me directly to the Cable Factory, where the conference was taken place, it was the place where early employees of Nokia started to develop their first phones. Arrived at 9.30 in the morning, it rained lightly outside, my first impression in any tech conference was the queue to register to get my badges, the organizers seemed to be very professional, they divided the badges to several difference booths by attendances’ last name, one could just jump in the queue with the last name and get the badge really fast. The info desk is right inside, where they provided me with all information about the locations, breakfast, restaurants, the stages. Breakfasts are included in the ticket conference, so the first thing I did was filling my stomach for the busy morning program ahead. In time to get back to the main stage where the Finnish prime minister Jyrki Katainen had his initial speech to officially open the conference, I heard how eager the leader of a high tech country was with his speech, applauded by the whole audience, then the keynote by Kristian Segerstråle was also very impressive, MCs announced that there were about 3000 people inside the venue, such a big number of people in a tech conference gathered by a non profit organization. After the lightning talks by David Gardner from EA and Jason Chein from Amazon, the team at Jolla Mobile officially launch the mobile operating system called Sailfish OS, the one developed by the team behind MeeGo of Nokia. I was not really looking for this but the whole audience seemed to be very supported, easily understood as most of them are Finnish. Finns can’t stand to see their biggest phone maker on the planet loosing their market shares to Apple, Google and Samsung. It’s promising, the team had their great demo. Hope they will become good player on the market. 

I did not have much time in the main stage, as I felt I need to talk to investors to introduce as fast as I can my application FMFinder. So I walked out, a lot of companies presenting their products in the stands, investors also have their own stands, but in the pitching stage, something caught my eyes, several small startups have their two-three minutes pitching to the judges and the audience, I sat down and listen to some of them, it happened to be the one I listened to on the very first day won the final price the day after, FishBrain. There are so many different things that happened in different places, I felt quite lost in the first day, one reason be that I did not spend time reading the agenda very carefully the day before, other be that there were so many startups participated that I gave up looking on each of the website of the companies on slush web page. Lunch time was the best time to talk, I had great time talking with several different people that sat down in the same table with me, only at lunch time, people are willing to talk most as I realized that during the event, you don’t have such a chance. Investors, developers, CEOs, founders, students, media reporters were all there eating the same dish as me, I was not lucky enough to get my application idea to the right person during lunch break, but I had great time talking to a couple of investors in their stands after that. There are several startups looking for funding, 500 of them and investors were limited, it was like 50 guys dating with a girl, you had to be stand out from the crowd for them to be considered. But I did not give up on presenting my application to a couple of them, VisionPlus, Tekes, Polte had their stands with someone to talk to, so I didn’t miss the chance. Other venture capitalists and angel investors I met during lunch break or inside the venue did not seem to be interested. I was so innocent to think that investors are the one that having money and startups are the one that need them, so let’s pitch to anyone I can see in their badge written “Investor”. Thing does not happen that way, I talked to some venture capitalists and angel investors, their interests are in very specific field of the industry, or sometimes only on a very high level of standards. I wish that on Slush website, there’s a section describing what the venture capitalists, angel investors are specializing on, the contact information, or at least their Twitter accounts to follow. Playing match game with dozens of investors seemed to be pretty hard. I asked the event assistant in the info desk if there’s a way to talk to investors, the only information that she can give me is the color of the badge of the investors, and that I could see them in the venue walking somehow. Hmm, that’s interesting. 

The first day event seemed to last for the whole night, after the event conference, the main stage was closed for the production of the TV channel MTV3, a Finnish broadcasting company, they had direct program that interviewed Peter Vesterbacka, the founder of Rovio Mobile and also the event organizers. The after party was provided by Supercell, a Finnish company that have two of the titles among the top grossing iOS games on the AppStore, Hay Day and Clash of Clans. Beers, wines, champagnes, fruit juices are always ready to be served, outside, they are grilling hot dogs on one side and on the other side, people are relaxing by entering to the sauna bus, that is typical Finnish culture, almost every house has their own sauna. The event organizer wants to bring that to the participants of Slush as well, I didn’t know about that sooner otherwise I also brought my own swim suit to enjoy! The party was the perfect time for networking, but unfortunately I had to come back to the hostel with the late night bus.

Second day of the conference, I brought my luggage and leave it at the cloakroom, the assistants were so nice, they always smiled when I brought them my luggage and got it back after the day. I spent the breakfast talking with a bunch of people, I presented my application FMFinder to them and got several suggestions such as how I could improve the UI for the app to look better, which color schemes I should use. Arrived in the main stage where there were several different speakers talking about design, it was so good to listen to them, I learned quite some lessons from leading designers in the industry. Although I had the feeling that one had a unprepared presentation, not sure if he drank so much the day before. I was tired after the lunch break so I decided to get into the stands to talk to other developers to see how they are doing, there are bunches of awesomenesses that developers, CEOs and founders all over Europe and Russia brought to the conference. Ovelin has been around for quite some years, but it’s the first time I know them, their product called Guitar Bots  is definitely the thing that I will try to learn to play guitar when I come back to Milan, using the guitar itself as a controller, one can play the guitar and on the screen, the virtual band will rock your afternoon, if you are a good guitar player then you’ll be a super star with this application. I listened to the presentation of Berggram in the Event stage, it seemed a huge amount of work had been spent on designing the Music Theory Automation. Deveo had the git hosting service themselves and it promised to give small team free hosting forever, so why not try their product? Rovio Mobile had their stand for two days, who does not know that they are the makers of several Angry Birds games in the AppStore, and the Holywood movie Angry Birds Rio. Holvi helps provide the banking solution to business owners the easiest way possible, their sale team was very helpful in giving me useful information to help my sister build her own payment website to help her guesses pay when they stay in her apartments in Turku. Info.gram sounds promising, as they revealed during the event in the Event Stage, several big media companies in the world use their service to generate infographics graph to put into the articles. Several others that I did not have enough time to write them down here. Check out the list of all startups on Slush webpage to find out by yourself!

In the main stage, the winner of the lightweight track finally was announced, FishBrain. Slush 2012 ended. I came back to Turku to stay for two days before taking the flight to go back to Milan, Italy. Hope I will be here in the conference next year with my own stand. Who knows?

About me:

Hoang Pham graduated from Ho Chi Minh City University of Technology, he spent two years working for a Danish company in Sai Gon, he was so bored that he decided to get a master degree in Politecnico di Milano, Italy. He has spent the last 3 years dedicating on iPhone/iPad development working as a consultant and an employee. In September 2012, he started his own company in Turku, Finland.

In the summer of 2012, Hoang Pham travelled to the United States from Italy to attend the World Wide Developer Conference 2012 in San Francisco taken place between 11th and 15th June, his very first time to attend such a conference. After the conference, he flied to Chicago to meet his long time friend Tuan Nhon from university in Ho Chi Minh City in Vietnam, and also in Politecnico di Milano in Italy. In Chicago, he talked to him about his PhD research, one of his research interest was data visualization, works such as visualization of a whole population were beautifully drawn in a graph, and another work that impressed Hoang Pham was how to display the song similarities in a graph. Hoang Pham came up with the idea to build an app on iPhone/iPad to visualize the songs/artists similarities. FMFinder came out as the result, music discovery and recommendations has never been so fun!

About FMFinder application:

FMFinder helps you to discover new music based on your tastes. Supposed you’re listening to a song on your Music application on iPhone/iPad, let’s say “Glad you came”, by “The Wanted”. You launch the app and tap on “Current playback song” on the left menu, the application will download automatically 16 songs similar to this one (by similar, it means, by rhythm, by artists, authors, other users listening preferences on last.fm. Further reference is on the Q&A on the website). Some similar songs that the app found are: “Where have you been, by Rihanna”, “What Makes You Beautiful, by The Wanted”, “Call Me Maybe, by Carly Rae Jepsen”, and many more. These songs are then displayed in a graph with each song represented by a node, these nodes connected to the center node which is the song you selected. Tapping on a song “Call Me Maybe” will bring up a new screen where you can then watch the video preview of the song, watch the related YouTube videos, and read the song facts, after the video preview finished playing, there are options to buy song audio/video on iTunes. In case you want to further discover the similar songs related to this one, you can easily tap on “View Related” button and the graph will be reloaded with the new data. The song “Call Me Maybe” will appear in the center node and the similar songs are surrounded by this one. Switching between “Songs” and “Artists” similarities is within a thumb, if you are viewing “Call Me Maybe”, switch to “Artists”, the app will show “Carly Rae Jepsen” in the center and similar artists to “Carly Rae Jepsen” are surrounded, such as: “Ellie Goulding”, “Cher Lloyd”, “Taylor Swift”, “Justin Bieber”. Tapping on an Artist, you can then watch all songs available on YouTube of the Artist, or read his/her biography. There’s also a quick link to go to the Artist page on iTunes. 

The most powerful feature of the application is the ability to recommend new music based entirely on your Music library, you can access your music library by Playlists, by Albums or by Artists. Songs are then available to select in the according categories, “music recommendation based on the ones that you already own, that’s a unique experience” - said Hoang Pham, CEO and Founder of Cosmo Studios.

What happens if you don’t have any music in your library, worry no more, the app has three categories to help you stay up to date with the trend: top last.fm songs, top iTunes songs, and top iTunes music videos. These categories bring you the latest songs from their site, with top last.fm songs the category is the worldwide one, while with iTunes songs and iTunes music videos, the category is based on the country in the Settings function. 

Still not satisfy with the provided categories? Then, search for the one you like, simply input the song title or the artist name in the search field, all of the songs with that title or from that artist will be displayed, scrolling through the list to find out the one you like, and tap on any song to watch the preview and related YouTube videos, find out the similar songs to the one you like. It’s that simple!

With the Settings function, you can increase or decrease the number of songs downloaded from last.fm or iTunes songs/music videos. Also, it’s possible to modify the graph to view more or less items, on the iPad, you may want to increase the number of items to view, while on the iPhone, this number you may want to decrease. 

The History section contains the list of songs that you have tapped so far, this helps you better navigate back and forth to the songs you want to discover. 

FMFinder has been created with all the love from a team of two enthusiasts developers, company registered in Turku, Finland.

Follow me on Twitter: @pnhoang


Sep 28

Gemfile install issue with Mountain Lion

I have been traveling for almost 4 months and so I have not updated the blog so far. This morning I ran a new Rails app and get this issue:

$ cd work

$ rails new test_app

…

An error occured while installing json (1.7.5), and Bundler cannot continue.

Make sure that `gem install json -v '1.7.5'` succeeds before bundling.

I found the solution on StackOverflow, which relates to the “Command line tools” not being installed by default on Mountain Lion for Xcode 4.3. The original post suggests downloading the “Command line tools” through Preferences panel of Xcode or through Apple’s download website. After installation, run the command:

$ sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer

And make the symbolic link on gcc-4.2 in order for make command to work

$ sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.2

That’s it. It should now solve the bundler install error.


Jun 1

Build a Rails backend API for an iPhone client

I have been an iOS developer for over three years, but I am a newcomer to Rails. I think the best way to learn Rails is to do a sample Todo list app with RESTFUL API and basic authentication, and because I want to review my iOS skills, I will write an iOS client to query the server’s API to show on the iPhone and iPad. Along the way, I will document the process of making these two projects and the source code for all two of them will be available on my Github account

The purpose of this entry is to learn Rails, so I will use a lot of techniques/frameworks/open source projects along the way:

  • I will use Twitter’s bootstrap framework to make the front end on the web look nicer
  • I will use Markdown for editing ToDo item, as sometimes I want to be able to show links in my ToDo item.
  • Many techniques from Railscasts’ Ryan Bates. I strongly suggest you subscribe to his site for $9/month because he always bring to the community the best knowledge.
  • Many techniques learned from Rails tutorial book by Michael Hartl.

Enough for the introduction, let’s get started.

Warning: Part 1 is pretty long and does not contain any iOS code yet!!!

PART 1: THE SERVER RAILS APP

Configuration

I use Rails 3.2.3 and Ruby 1.9.2 for the server and iOS 5 SDK with Xcode 4.2 for the client. 

Todo project with Rails

Let’s create the project using the rails new command

$ cd work
$ rails new todo-app
$ cd todo-app
$ git init 
$ git add . 
$ git commit -m "Initial Rails project"

At this time, we already have a running Rails app, if we want to see what’s already there, we can try:

$ rails server

And then we can open the Chrome browser, type http://localhost:3000/ and the magic default Rails homepage will appear

We don’t need just that, we’ll soon delete that homepage, for now, let’s open the project in the editor so that we can make some modifications

$ mate .

My favorite editor of choice is TextMate, and here I use the mate command line to open the current directory, which is now the whole Rails application.

Let’s edit the gemfile,  to add Twitter bootstrap gems to our project, we’ll use the twitter-bootstrap-rails gem because it provides us with some useful commands to speedup our process.

group :assets do
     ...
     gem 'twitter-bootstrap-rails'
end

Then I’ll run the bundle command to install the new gem:

$ bundle install

After that we’ll run the rails generate command to install the bootstrap

$ rails generate bootstrap:install 

You’ll notice that there are some javascript, css and less files installed in your assets folder in the Rails app. That means that we are ready to have Bootstrap supported in our application. Now let’s create our first model view controller (MVC) ToDo item using the rails generate scaffold command, our todo will have only two fields: item for storing the todo, completed_at for storing the completion date, if it is nil then it’s not yet done, and then we migrate the database using the rake command. (You’ll notice that there’s something wrong here, the completed_at should be datetime, we’ll see how to fix our schema later)

$ rails generate scaffold todo item:text completed_at:date --skip-stylesheets
$ rake db:migrate

We use the —skip-stylesheets command to avoid using the stylesheets generated by the scaffold, as we want to use the bootstrap stylesheets.

The gem twitter-bootstrap-rails comes with some handy functions to enable our application to have the nice layout, we’ll use the rails generate bootstrap:layout command to have our application a fixed layout

$ rails generate bootstrap:layout application fixed

At this time, if we run the rails server command, then we’ll see a nice layout applied to our todos page, it automatically adds a nav bar and a side bar to our project and apply the correct CSS classes to the page, http://localhost:3000/todos 

 We are really happy now, and we go ahead to apply the bootstrap’s themed to our todos resource, the gem we used has another command to generate the themes as follows:

$ rails generate bootstrap:themed todos

When run this command, it will ask for the resolution of conflicts, but it’s ok to answer Y (YES) to all the questions. You can run the generate command with -f option to force all to override the conflicts with the ones from bootstrap. Now we have a pretty complete and beautiful Todo app, we can navigate to create new todo, update, delete them.

Adding new todo item:

And the new listing Todos page looks like this:

Now let’s add some validation to our code, we don’t want a Todo item to not have any text, but before doing that, we run the test to see if the auto generated ones pass

$ rake test
Finished in 0.004226 seconds.

0 tests, 0 assertions, 0 failures, 0 errors, 0 skips

Finished in 0.440987 seconds.

7 tests, 10 assertions, 0 failures, 0 errors, 0 skips

Let’s open the model file in app/models/todo.rb and add the validation for todo’s item

class Todo < ActiveRecord::Base
  attr_accessible :completed_at, :item
  
  validates :item, presence: true
end

Now if we open the rails console and try to create a new todo item without specifying the item text, then it will fail:

$ rails console --sandbox
Loading development environment in sandbox (Rails 3.2.3)
Any modifications you make will be rolled back on exit
1.9.2p290 :001 > todo = Todo.new(item: "")
 => # 
1.9.2p290 :002 > todo.save
   (0.3ms)  SAVEPOINT active_record_1
   (0.1ms)  ROLLBACK TO SAVEPOINT active_record_1
 => false 
1.9.2p290 :003 > todo.valid?
 => false 
1.9.2p290 :004 > todo.errors.full_messages
 => ["Item can't be blank"] 
1.9.2p290 :005 > quit
   (0.2ms)  rollback transaction

Let’s go ahead and add the alert when we successfully create/update a todo item. Open the app/views/layouts/application.html.erb and add the following code:

    <div class="container">
      <div class="content">
        <% flash.each do |name, msg| %>
          <div class="alert alert-<%= name == :notice ? "success" : "error" %>">
            <a class="close" data-dismiss="alert" href="#">x</a>
            <%= msg %>
          </div>
        <% end %>
        ...

Now when we create/update an item, there will be an alert with the corresponding message and a close button to dismiss it.

Next, we also want to add the simple_form gem into our application so that the validation of the fields in the form work. This gem will help us generate the correct stylesheets class for our form’s fields and additionally install Bootstrap CSS classes for us.

First we need to add gem ‘simple_form’ to the end of our gemfile:

...
gem 'simple_form'

Then we run the simple_form:install command to generate the configuration and scaffold template:

$ rails generate simple_form:install --bootstrap
       exist  config
      create  config/initializers/simple_form.rb
      create  config/locales/simple_form.en.yml
      create  lib/templates/erb/scaffold/_form.html.erb
===============================================================================

  Be sure to have a copy of the Bootstrap stylesheet available on your
  application, you can get it on http://twitter.github.com/bootstrap.

  Inside your views, use the 'simple_form_for' with one of the Bootstrap form
  classes, '.form-horizontal', '.form-inline', '.form-search' or
  '.form-vertical', as the following:

    = simple_form_for(@user, :html => {:class => 'form-horizontal' }) do |form|

===============================================================================

Next, we need to change form_for function to use simple_form_for and just let simple_form handle the correct types of form fields for us, like so:

# app/views/todos/_form.html.erb

<%= simple_form_for @todo, :html => { :class => 'form-horizontal' } do |f| %>

  <%= f.input :item %>
  <%= f.input :completed_at %>
   
  ...
<% end %>

# app/views/todos/_form_new.html.erb
<%= simple_form_for @todo, html: { class: 'form-horizontal'} do |f| %>
  
  <%= f.input :item %>
  
  ...
<% end %>

Now that when an item is created with blank, then the error will be displayed nicely like this:

Use Markdown to highlight Todo items

At this stage, we are quite happy now with our product, but here we want to go further, let’s enable our wonderful users to use Markdown to create/edit their Todo items, how great is that? When creating their Todo item, for example, “Read the Ruby on Rails tutorial”, they can easily create “Read the [Ruby on Rails tutorials](http://ruby.railstutorial.org)”, and the Todo item will be nicely converted to “Read the Ruby on Rails tutorials

Notice: in this section, I use the materials that come from the Pro version of railscasts.org 207 Syntax highlighting revised, please consider support Ryan Bates by subscribing to his site for only 9$/month.

We are going to need two new gems, pygments.rb and redcarpet. Let’s go ahead and add them into our gemfile, remember to run the $ bundle install command after that:

# Gemfile
..
gem "pygments.rb", "~> 0.2.12"
gem 'redcarpet'


In order to use the Pygments.rb syntax highlighting, we need to add Pygments.css to our project, luckily, the function Pygments.css add this file to our project for us, so we are going to create a new file pygments.css.erb in our assets/stylesheets folder

# /app/assets/stylesheets/pygments.css.erb
<%= Pygments.css %>

Now if we restart our server with $ rails server, we may encounter a crash of the whole rails application, it’s because Pygments is the syntax highlighting on the Server side written in Python, Ruby gem pygments.rb is the Ruby port of this Python program, it executes Python code using Python binary, if your system has the 32-bit only Python, you may encounter the error:

Could not open library '/Library/Frameworks/Python.framework/Versions/2.7/lib/libPython2.7.dylib': dlopen(/Library/Frameworks/Python.framework/Versions/2.7/lib/libPython2.7.dylib, 9): no suitable image found. Did find:
/Library/Frameworks/Python.framework/Versions/2.7/lib/libPython2.7.dylib: no matching architecture in universal wrapper
(in /Users/pnhoang/Developer/rails_casts/railscasts-episodes/episode-207/revised/highlighter-after/app/assets/stylesheets/pygments.css.erb)

Download and install the 64bit binary Python will solve this problem.

Next step is to add a new class HTMLwithPygments and a function markdown into our ApplicationHelper

#/app/helpers/application_helper.rb
module ApplicationHelper
  class HTMLwithPygments < Redcarpet::Render::HTML
    def block_code(code, language)
      sha = Digest::SHA1.hexdigest(code)
      Rails.cache.fetch ["code", language, sha].join('-') do
        Pygments.highlight(code, lexer: language)
      end
    end
  end

  def markdown(text)
    renderer = HTMLwithPygments.new(hard_wrap: true, filter_html: true)
    options = {
      autolink: true,
      no_intra_emphasis: true,
      fenced_code_blocks: true,
      lax_html_blocks: true,
      strikethrough: true,
      superscript: true
    }
    Redcarpet::Markdown.new(renderer, options).render(text).html_safe
  end
end

The functions defined in /app/helpers/ folder are automatically available in the controllers and the views, so we can call markdown from our show.html.erb and index.html.erb as below:

# /app/views/todos/index.html.erb
  ..
        <td><%= markdown todo.item %></td>  
  ..

# /app/views/todos/show.html.erb
  ..
  <dd><%= markdown @todo.item %></dd>
  ..

Now we can edit and update our Todo items with Markdown, the results are shown in this figure:

Add Pagination into Todo items

One more twist we would like to add is the pagination into Todo items list page, suppose, you have 20 items in your Todo list, you would like to show only 5 items per page. That’s easy to do with Rails. We’ll use two new gems ‘will_paginate’ and the ‘bootstrap-will_paginate’ gem to configure ‘will_paginate’ to use Bootstrap stylesheets, and as usual, after adding the new gem, we need to run the $ bundle install command and restart the server.

# file: Gemfile
...
gem 'will_paginate'
gem 'bootstrap-will_paginate'

In order to use this gem, we just need to add a Ruby function call to will_paginate at the bottom of the index page.

# file: /app/views/todos/index.html.erb
...
<%= will_paginate %>

<%= link_to t('.new', :default => t("helpers.links.new")),
            new_todo_path,
            :class => 'btn btn-primary' %>

and changing our controller to call the ‘paginate’ function of the Todo model.

# file: /app/controllers/todos_controller.rb
  def index
    @todos = Todo.paginate(page: params[:page], per_page: 5)
    ...

And now, we have our awesome pagination for Todo items:

Fixing the database schema

I accidentally created the table todos with the column completed_at as date, it was wrong, either it should be a datetime column or it should be renamed completed and the data type is boolean. So let’s fix that before we go ahead on adding the Todo Lists to the database schema. The rule of thumb when handling errors in the schema is to create another migration to fix it.

Let’s first generate the migration using the generate command:

# 
$ rails generate migration ChangeTodoTable

When creating a migration to change a table’s structure, Rails does not support the change method so we need to define both the up and down functions. In the up function, we specify how we want to change the database forward, conversely, in the down function, we specify how to return back to the previous state. This implies that by doing an up and down, the database should come back to the current state. In our case, when we add a completed column with value true/false, we will populate the corresponding true/false value into column completed based on the completed_at date column, this requires us to do a loop through all rows in Todo table, after that, we will remove column completed_at. Hence the up function is as follows:

# db/migrate/20120521121851_change_todo_table.rb
class ChangeTodoTable < ActiveRecord::Migration
  def up
    change_table :todos do |t|
      t.boolean :completed
      Todo.all.each do |todo|
        if todo.completed_at != nil
          todo.update_attributes! completed: true
        else
          todo.update_attributes! completed: false
        end        
      end
      t.remove :completed_at
    end
  end

  def down
    ...
  end
end

With the up function in place, we need to set the attrs_accessible to completed in our model, otherwise Rails will complaint about mass assigned values error

# app/models/todo.rb
class Todo < ActiveRecord::Base
  attr_accessible :completed_at, :item, :completed
  
  ...
end

Now we can run the $ rake db:migrate command to see the changes reflected in the database. We can open the Rails console to see the changes in action.

# BEFORE MIGRATION

$ rails c
Loading development environment (Rails 3.2.3)
1.9.2p290 :001 > Todo.first
  Todo Load (0.1ms)  SELECT "todos".* FROM "todos" LIMIT 1
 => #<Todo id: 5, item: "Read the [Ruby on Rails Tutorials](http://ruby.rail...", created_at: "2012-05-16 16:14:05", updated_at: "2012-05-21 13:00:39", completed_at: "2012-05-21"> 

$ rake db:migrate

# AFTER MIGRATION
$ rails c
Loading development environment (Rails 3.2.3)
1.9.2p290 :001 > Todo.first
  Todo Load (0.1ms)  SELECT "todos".* FROM "todos" LIMIT 1
 => #<Todo id: 5, item: "Read the [Ruby on Rails Tutorials](http://ruby.rail...", created_at: "2012-05-16 16:14:05", updated_at: "2012-05-21 13:20:39", completed: true> 


With the down function, we just need to do the reverse process, first we add the completed_at as date data type, then we loop through all Todo rows and update the completed_at with the latest date of updated_at. (Notice: this is not really correct down migration, though for us now, it’s not too important the exact completed_at date)

# db/migrate/20120521121851_change_todo_table.rb
class ChangeTodoTable < ActiveRecord::Migration
  def up
    ...
  end

  def down
    change_table :todos do |t|
      t.date :completed_at
      Todo.all.each do |todo|
        if todo.completed == true
          todo.update_attributes! completed_at: todo.updated_at.to_date
        else
          todo.update_attributes! completed_at: nil
        end
      end
      t.remove :completed
    end    
  end
end

If you want to try to rollback, just try $ rake db:rollback and now the database schema is the same as before. Though we don’t want to run it now. Just for completeness, we write the down function.

After running the $ rake db:migrate command, we can remove the :completed_at from the attr_accessible of Todo model

# app/models/todo.rb
class Todo < ActiveRecord::Base
  attr_accessible :item, :completed
  
  ...
end

And also be able to remove the _form_new.html.erb from folder app/views/todos/, as now we don’t need a separate form for creating new Todo. In the app/views/todos/new.html.erb, we can revert back to use render :partial ‘form’

# 
...
<%= render :partial => 'form' %>

Everywhere we have the completed_at, we should now change to completed, luckily because we use simple_form_for for our attributes, we don’t need to re-create the form’s field for completed. simple_form_for is intelligent enough to use the checkbox in place for completed field

# app/views/todos/show.html.erb
  <dt><strong><%= model_class.human_attribute_name(:completed) %>:</strong></dt>
  <dd><%= @todo.completed %></dd>

# app/views/todos/index.html.erb
...
      <th><%= model_class.human_attribute_name(:item) %></th>
      <th><%= model_class.human_attribute_name(:completed) %></th>
      <th><%= model_class.human_attribute_name(:created_at) %></th>
...

        <td><%= markdown todo.item %></td>
        <td><%= check_box_tag :completed, todo.completed.to_s,  todo.completed, disabled: true %></td>
        <td><%=l todo.created_at %></td>

Add Todo lists to database schema

We are almost ready with the Todo items so far, but as our Todo items grow, we need to organize the Todo items into lists. The next iteration we will make is to generate the scaffold for Todo lists

$ rails generate scaffold List name:string --skip-stylesheets

$ rails generate bootstrap:themed lists -f

With the generate scaffold command, we don’t want to generate the scaffold stylesheets, so we pass the option —skip-stylesheets to the generator. Right after creating the scaffold, we want to apply the Bootstrap theme into the List views, so we run the generate bootstrap:themed command with -f option to force the changes in case there is conflict.

We need to have a reference from Todo item table to List table, so we create a database migration and then modify the change function

$ rails generate migration AddReferencesToTodo

# db/migrate/add_reference_to_todo.rb
class AddReferencesToTodo < ActiveRecord::Migration
  def change
    change_table :todos do |t|
      t.references :list
    end
  end
end

In the model classes, we need to define some relationships: a List has many Todos, and conversely, Todo belongs to a List. We also declare the relationship between Lists and Todos with dependent: :destroy, because  we want to delete all of a list’s Todo items whenever we delete a list. This declaration is necessary in the parent item, not the child item.

# app/models/list.rb
class List < ActiveRecord::Base
  attr_accessible :name
  
  has_many :todo, dependent: :destroy
end

# app/models/todo.rb
class Todo < ActiveRecord::Base
  ...
  belongs_to :list
end

And we would like to have the default value for completed as false instead of nil. First we need to add a callback to the after_initialize event, this callback function will then initialize the values of the instance of the class. Here’s the full Todo model up to this point

class Todo < ActiveRecord::Base
  attr_accessible :item, :completed
  after_initialize :default_values
  
  validates :item, presence: true
  belongs_to :list
  
  private
    def default_values
      self.completed ||= false
    end
end

Update the routes to nested resources

With our model ready, we can now update the routes to have nested resources. The concept is simple, one list has many todo items, so Todo items should be included in lists. In Rails routing, we do as follows

# /config/routes.rb
  resources :lists do
    resources :todos
  end

We can see all the routes that Rails created for us with $ rake routes command. These includes 7 restful resource routes for parent element: list and 7 restful resource routes for child element: todo within a list. The child element is accessed by using the /lists/:list_id/ path, all Todo items path starts with this prefix.

$ rake routes
        list_todos GET    /lists/:list_id/todos(.:format)          todos#index
                   POST   /lists/:list_id/todos(.:format)          todos#create
     new_list_todo GET    /lists/:list_id/todos/new(.:format)      todos#new
    edit_list_todo GET    /lists/:list_id/todos/:id/edit(.:format) todos#edit
         list_todo GET    /lists/:list_id/todos/:id(.:format)      todos#show
                   PUT    /lists/:list_id/todos/:id(.:format)      todos#update
                   DELETE /lists/:list_id/todos/:id(.:format)      todos#destroy
             lists GET    /lists(.:format)                         lists#index
                   POST   /lists(.:format)                         lists#create
          new_list GET    /lists/new(.:format)                     lists#new
         edit_list GET    /lists/:id/edit(.:format)                lists#edit
              list GET    /lists/:id(.:format)                     lists#show
                   PUT    /lists/:id(.:format)                     lists#update
                   DELETE /lists/:id(.:format)                     lists#destroy

The effect of adding nested resources into Todo items is that now we are not able to access Todo items anymore. There’s no way to create/edit/show/list todo items at the moment. However, adding this nested resource allows us to have a lot of new paths to access the todo items from the list. For example, we can see from above, to get the list of todo items of a specific list, we have the list_todos GET, this means that we can use the list_todos_path(@list) or list_todos_url(@list) to access the Todo list index page of a list.

We’ll make a small change to the show method of lists_controller to have a way to go back and forth. Let’s use Twitter boostrap’s breadcrumb to do this.

# /views/lists/show.html.erb
<%- model_class = @list.class -%>
<ul class="breadcrumb">
  <li>
    <%= link_to 'My Lists', lists_path() %>
    <span class="divider">/</span>
  </li>
  <li>
    <%= link_to 'Edit This List', list_todos_path(@list) %>
    <span class="divider">/</span>
  </li>
  <li class="active">
    <a href="#">Current List</a>
  </li>
</ul>

<h1><%=t '.title', :default => model_class.model_name.human %></h1>
...

While we are at show view, we add a method to add new Todo items and to view the existing Todo items if any. In case there is todo item, we want to render the whole collection, Rails will enumerate each item in the collection and apply the render partial on each item. As a result, we need to create a new partial _todo.html.erb in app/views/todos folder

<% if @list.todos.any? %>
  <h2>Todo items</h2>
  <%= render @list.todos %>
<% end %>

<h2>Add todo item</h2>
<%= render "todos/form"%>

When displaying the Todo items, we also want to use Markdown to highlight its syntax. Besides, for completed todo item, we will use Rails’s check_box_tag function to display a checkbox aside. Currently, we will disable this checkbox, as we have not had yet the Ajax function to enable checking/unchecking the completed status of a Todo item.

# app/views/todos/_todo.html.erb
<%- model_class = todo.class -%>

<dl class="dl-horizontal">
  <dt><strong><%= model_class.human_attribute_name(:item) %>:</strong></dt>
  <dd><%= markdown todo.item %></dd>
  <dt><strong><%= model_class.human_attribute_name(:completed) %>:</strong></dt>
  <dd><%= check_box_tag :completed, todo.completed.to_s, todo.completed, disabled: true %></dd>
</dl>

The command render todos/forms use a partial in app/views/lists called _form.html.erb. In this form, we will use simple_form_for to simplify the form generation. It comes with default error management on each form fields compatible with bootstrap

# app/views/lists/_form.html.erb
<%= simple_form_for @list, :html => { :class => 'form-horizontal' } do |f| %>
  <%= f.input :name %>
  <div class="form-actions">
    <%= f.button :submit, :class => 'btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                lists_path, :class => 'btn' %>
  </div>
<% end %>

Now we should be able to add new Todo items to the List and view all of a list’s items. We can use Markdown syntax to add our Todo item, an example is shown below:

And here’s the result in the listings page:

Advertisement: I’ll be participating in this year’s WWDC event. I would be very happy to meet all of you. Follow me on Twitter: @pnhoang

Fixing the Todo items controller

We are now able to view the list and add items into it. However, we would like to fix the existed Todo item controller that we already did. The first one is the index, instead of directly getting the Todo from the params[:todo_id], we now have to first get the list from params[:list_id] and then use this list to find the todo items. 

# app/controllers/todos_controller.rb
  def index
    @list = List.find(params[:list_id])
    @todos = @list.todos.paginate(page: params[:page], per_page: 5)
    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @list }
    end
  end

In the view page, we need to replace the @todos variable with @list.todos, and the corresponding paths, for example, todo_path(@todo) will be list_todo_path(@list, todo) and edit_todo_path(@todo) will be edit_list_todo_path(@list, todo), new_todo_path will be new_list_todo_path. For reference, here is the full index page

<%- model_class = Todo.new.class -%>
<ul class="breadcrumb">
  <li>
    <%= link_to 'My Lists', lists_path() %>
    <span class="divider">/</span>
  </li>
  <li>
    <%= link_to 'View This List', list_path(@list) %>
    <span class="divider">/</span>
  </li>
  <li class="active">
    <a href="#">Current List</a>
  </li>
</ul>

<h1><%= @list.name %></h1>
<table class="table table-striped">
  <thead>
    <tr>
      <th><%= model_class.human_attribute_name(:id) %></th>
      <th><%= model_class.human_attribute_name(:item) %></th>
      <th><%= model_class.human_attribute_name(:completed) %></th>
      <th><%= model_class.human_attribute_name(:created_at) %></th>
      <th><%=t '.actions', :default => t("helpers.actions") %></th>
    </tr>
  </thead>
  <tbody>
    <% @todos.each do |todo| %>
      <tr>
        <td><%= link_to todo.id, list_todo_path(@list, todo) %></td>
        <td><%= markdown todo.item %></td>
        <td><%= check_box_tag :completed, todo.completed.to_s,  todo.completed, disabled: true %></td>
        <td><%=l todo.created_at %></td>
        <td>
          <%= link_to t('.edit', :default => t("helpers.links.edit")),
                      edit_list_todo_path(@list, todo), :class => 'btn btn-mini' %>
          <%= link_to t('.destroy', :default => t("helpers.links.destroy")),
                      list_todo_path(@list, todo),
                      :method => :delete,
                      :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')),
                      :class => 'btn btn-mini btn-danger' %>
        </td>
      </tr>
    <% end %>
  </tbody>
</table>


<%= will_paginate %>

<%= link_to t('.new', :default => t("helpers.links.new")),
            new_list_todo_path,
            :class => 'btn btn-primary' %>

We also edit the show action by first locating to the params[:list_id] for list variable, then from this list, locating the todo item with params[:id].

  def show
    @list = List.find(params[:list_id])
    @todo = @list.todos.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @list }
    end
  end

In the view page, we also need to change the paths

<div class="form-actions">
  <%= link_to t('.back', :default => t("helpers.links.back")),
              list_todos_path(@list), :class => 'btn'  %>
  <%= link_to t('.edit', :default => t("helpers.links.edit")),
              edit_list_todo_path(@list, @todo), :class => 'btn' %>
  <%= link_to t('.destroy', :default => t("helpers.links.destroy")),
              list_todo_path(@list, @todo),
              :method => 'delete',
              :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')),
              :class => 'btn btn-danger' %>
</div>

We can repeat the process for other actions in the controller: new, edit, create, update, destroy. Here is the remaining of the todos controller

# app/controllers/todos_controller.rb
  ...
  def new
    @list = List.find(params[:list_id])
    @todo = @list.todos.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @todo }
    end
  end

  def edit
    @list = List.find(params[:list_id])
    @todo = @list.todos.find(params[:id])
  end


  def create
    @list = List.find(params[:list_id])
    @todo = @list.todos.build(params[:todo])
    
    respond_to do |format|
      if @todo.save
        format.html { redirect_to list_todos_path(@list), notice: 'Todo item was successfully created.' }
        format.json { render json: @list, status: :created, location: @list }
      else
        format.html { render action: "new" }
        format.json { render json: @todo.errors, status: :unprocessable_entity }
      end
    end
  end


  def update
    @list = List.find(params[:list_id])
    @todo = @list.todos.find(params[:id])

    respond_to do |format|
      if @todo.update_attributes(params[:todo])
        format.html { redirect_to list_todo_url(@list, @todo), notice: 'Todo was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @todo.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /todos/1
  # DELETE /todos/1.json
  def destroy
    @todo = Todo.find(params[:id])
    @todo.destroy

    respond_to do |format|
      format.html { redirect_to todos_url }
      format.json { head :no_content }
    end
  end

Last thing we need to do is to change the form for creating, updating Todo item. We should have an array of two objects for @list and @todo, we would normally write simple_form_for [@list, @todo]. However, in the case of @todo is empty such as when creating a new Todo from the list view page, we need to populate the form with Todo item fields. We do that by calling @list.todos.build method.

# app/views/todos/_form.html.erb

<%= simple_form_for [@list, if @todo.nil? then @list.todos.build else @todo end], :html => { :class => 'form-horizontal' } do |f| %>

  <%= f.input :item, input_html: {class: "span6", rows: 3}  %>
  <%= f.input :completed%>

  <div class="form-actions">
    <%= f.submit 'Save', :class => 'btn btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                lists_path, :class => 'btn' %>
  </div>
<% end %>

In the above, we also change the style class of item input, we use bootstrap’s grid system to expand our input text field to span6, and 3 rows.

The index.html.erb and show.html.erb for todo items do not change because we just render the partial form.

Adding user authentication

We are pretty happy now, we have our model with Todo lists and items, with item that supports Markdown syntax. However, we have not yet the user model. We would like to allow user to sign up, sign in and sign out. Upon sign up, user will be sign in immediately. On sign in, we want a way to restrict access to lists and todo items to only signed in users. Other users could not see the other user’s lists and items.

First we need to create user model, for simplicity, here we just create user model with only email and password. The password column will be named password_digest, we use features of Rails 3.1 for handling secure password in the database. When defining has_secure_password, two columns  password and password_confirmation will be automatically created for us. 

# Terminal
$ rails generate resource user email:string password_digest:string
$ rake db:migrate

Then we run the migration to create the schema in the database.

In the user model, we need to define has_secure_password so Rails will handle the creation of the secure hash password_digest column and the related password and password_confirmation. We also want to specify the attr_accessible methods for :email, :password and :password_confirmation

class User < ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation
  
  has_secure_password
  validate :password, presence: true
  validate :email, presence: true
end

We also need to uncomment the bcrypt gem in the gem file for the has_secure_password to work

# /app/gemfile
...
gem 'bcrypt-ruby', '~> 3.0.0'

Within the users controller, we will create two actions: new and create, in order to create a new form for user sign up and handle form submission. The new action will be use to generate the form with simple_form_for and the create action to handle the form submission

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to root_url, notice: "Signed up!"
    else
      render "new"
    end
  end
end

To show the form for sign up, as we said above, we will use simple_form_for to generate the form that is compatible with Twitter bootstrap and has the default error handling, which we already use throughout the article. Here we use three fields: email, password and password_confirmation

# app/views/users/new.html.erb
<h1>Sign Up</h1>

<%= simple_form_for(@user, html: { class: "form-horizontal"}) do |f| %>
  <%= f.input :email %>
  <%= f.input :password %>
  <%= f.input :password_confirmation %>
  <div class="form-actions">
  <%= f.button :submit, class: "btn-primary"%>
  <%= submit_tag 'Cancel', type: 'reset', class: 'btn btn-danger'%>
  </div>
<% end %>

Now we need a link to go to this sign up form. The form can now be accessible at /users/new path, however, we want to customize it a little bit, we want the link to be /signup. Let’s modify it in the routes.rb file

# config/routes.rb

  match '/signup', to: 'users#new'
  ...

This declaration makes available the signup_path and signup_url to use in our views. Restarting the server and navigating to the http://localhost:3000/signup now and it works!

Creating a new user by inserting an email and password with password confirmation inserted correctly, we will be able to create a new user in the database. 

Now we need a way for users to sign in, we will use Rails session to store the current user_id of signed in user. We generate the sessions controller with three actions: new, create and destroy. The new action will be used for login form, the create action for handling login submission and destroy for signing out.

# Terminal
$ rails generate controller sessions new create destroy

Again we change the routes to get prettier paths instead of sessions/new path and sessions/destroy path

# config/routes.rb
  match '/signin', to: 'sessions#new'
  match '/signout', to: 'sessions#destroy', via: :delete
  resources :sessions, only: :create
  ...

We now create the Login form with two fields: email and password. This time we use the form_tag to sessions_path because we don’t have any model to use with simple_form_for and form_for. The form_tag gets a bit complicated because we have to put the code for Twitter bootstrap ourselves.

# app/views/sessions/new.html.erb
<h1>Log in</h1>

<%= form_tag sessions_path, class: 'form-horizontal' do %>
  <div class="control-group email">
    <%= label_tag :email, nil, class: 'email control-label' %>
    <div class="controls">
      <%= text_field_tag :email, params[:email], class: 'string email' %>
    </div>
  </div>
  <div class="control-group password">
    <%= label_tag :password, nil, class: 'password control-label' %>
    <div class="controls">
      <%= password_field_tag :password %>
    </div>
  </div>
  <div class="form-actions">
    <%= submit_tag "Log in", class: 'btn btn-primary' %>
    <%= link_to 'Cancel', root_path, class: 'btn'%>
  </div>
<% end %>

Now to handle the login form submission, we need to implement the create action for sessions controller. We will first find the email to find the user in the database and use the password from the form to authenticate this user only in case this user exists in the database. Once authorized, we want to save the :user_id in the session with user’s id. This session will be used to check if a user is signed in to the system or not.

# app/controllers/sessions_controller.rb
  def create
    user = User.find_by_email(params[:email])
    if user && user.authenticate(params[:password])
      user.api_keys.create!
      session[:user_id] = user.id
      redirect_to lists_url, notice: "Logged in!"
    else
      flash.now.alert = "Invalid email or password"
      render "new"
    end
  end

Navigating now to the http://localhost:3000/signin, we can see the form to enter email and password. If the email and password are entered incorrectly, the user will receive a ‘invalid email or password’ message, otherwise, they would be noticed with ‘Logged in!’. Our signup, signin forms now work!

While we are at the sessions controller, let’s also implement a way for user to sign out, just set the :user_id hash in session to nil, then redirecting to root_url and we’re done.

# app/controllers/sessions_controller.rb
  def destroy
    session[:user_id] = nil
    redirect_to root_url, notice: "Logged out!"
  end

When user is signed in, we want them to navigate between pages in the application and if we don’t have any way to know if the user is signed in or not, then the user will have to signed in again. Let’s go ahead and define the current_user method in application_controller so all our controllers know who the current user is. We store this information in a local variable @current_user so the query into the database happens only once.

# app/controllers/application_controller.rb
  protect_from_forgery
private 
  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end
  helper_method :current_user
  ...

The helper_method :current_user makes this method available also in the views.

Updating the application layout

We have almost finished the signing mechanism, now we would like to display the links to users in the navigation menu. When user is not signed in, we display two links: sign in and sign up. When user is signed in, we show the link to sign out. This will be done using the dropdown menu provided by bootstrap. The code becomes larger in our application layout file, so let’s move it to a partial. We call it _header.html.erb, and in the application.html.erb we will render this partial

# app/views/layouts/application.html.erb
  <body>

    <%= render 'layouts/header' %>

    <div class="container">
    ...

Now we need to create the _header.html.erb in the app/views/layouts directory and make the change to the navigation menu. We change the name of the project to Markdown Todo, and use the root_path to link to the homepage, we check for the current_user, if the current user is signed in, then we display the dropdown with the menu to Account page, profile page, and settings page, also we display the sign out link. If user is not signed in, we just shown the signin_path and signup_path

# app/views/layouts/_header.html.erb
<div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container">
      <a class="btn btn-navbar" data-target=".nav-collapse" data-toggle="collapse">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <%= link_to "Markdown Todo", root_path, class: "brand" %>
      <div class="container nav-collapse">
        <ul class="nav">
          <li><%= link_to("Home", root_path) %></li>
          <li><%= link_to("About", "#") %></li>
          <li><%= link_to("Blog", "http://pnhoang.tumblr.com") %></li>
          
          <% if current_user %>
          <li id="fat-menu" class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Account <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
              <li><%= link_to "Profile", current_user %></li>
              <li><%= link_to "Settings", edit_user_path(current_user)%></li>
              <li class="divider"></li>
              <li>
                <%= link_to "Sign out", signout_path, method: :delete %>
              </li>
            </ul>
          </li>
          <% else %>
            <li> <%= link_to "Sign in", signin_path %></li>
            <li> <%= link_to "Sign up", signup_path %> </li>
          <% end %>
        </ul>
      </div><!--/.nav-collapse -->
    </div>
  </div>
</div>

We also want to move the head into a separate partial call _head.html.erb so the application layout code is simpler.

# app/views/layouts/application.html.erb
  <head>
    <%= render 'layouts/head' %>
  </head>

The _head.html.erb partial does not contain any new code. We show it here for reference:

# app/views/layouts/_head.html.erb

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for?(:title) ? yield(:title) : "Markdown Todo" %></title>
<%= csrf_meta_tags %>

<!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
<![endif]-->

<%= stylesheet_link_tag "application", :media => "all" %>

<link href="images/favicon.ico" rel="shortcut icon">
<link href="images/apple-touch-icon.png" rel="apple-touch-icon">
<link href="images/apple-touch-icon-72x72.png" rel="apple-touch-icon" sizes="72x72">
<link href="images/apple-touch-icon-114x114.png" rel="apple-touch-icon" sizes="114x114">

Now we would like to restrict access to lists to only signed in users (later on we will make changes to the schema to restrict access to only the correct user that signed in). Within our lists_controller and todos_controller, we can add the before_filter :authorize

# app/controllers/lists_controller.rb
class ListsController < ApplicationController
  before_filter :authorize
  ...

# app/controllers/todos_controller.rb
class TodosController < ApplicationController
  before_filter :authorize
  ...

The authorize method in the application controller is just as simple as checking the current_user variable, if it is nil then we redirect to the sign in page.

# app/helpers/application_controller.rb
  def authorize
    redirect_to signin_url, alert: "Not authorized" if current_user.nil?
  end

Now if we tried to navigate to lists index page without signing in, we will be redirected to the home page.

Adding static pages into the project

Up to now our root page is still the lists page where everyone if logged in can see all the todo lists and todo items. That is not quite right, we’ll fix it later. Now we want to make a nice welcome page to our project and make it the default root page.

Let’s start by creating a new controller

# Terminal
$ rails generate controller static_pages home about

The home page will have a hero-unit in a div with a big welcome and some sections. You can make it as fancy as you want.

# app/views/static_pages/home.html.erb
<div class="hero-unit">
  <h1>Welcome to Markdown Todo</h1>
  <p> Your Todo Items are awesome with Markdown! 
  </p>
  <p>
    Use all the available syntax at <a alt="Markdown" href="http://daringfireball.net/projects/markdown"> Markdown project</a> to create your Todo items
  </p>
  <p>
    <%= link_to "Sign up now !", signup_path, class: 'btn btn-primary btn-large' %>
</div>

The important thing is to change the routes config to the new controller’s action accordingly and remove the public/index.html

# config/routes.rb
  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  root :to => 'static_pages#home'

Our new nice home page:

Enabling JSON API

We have almost finished our application, let us now enable the JSON api so client applications can access our server app. JSON is by default configured with Rails app, when we create a scaffold, JSON is already enabled. Our problem is that we have use the authorize function to restrict access on the web using session. But with an API, we could not use the session, we need a way for the client application to specify authorization token in the header. An example is shown below

# Terminal
$ curl http://localhost:3000/lists -H 'Authorization: Token token="34b9d9eb4943786a791aecb366d91613"'

We go ahead and create a new model to keep the access_token for a user id and run the migration

# Terminal
$ rails generate model api_key access_token:string user_id:integer
$ rake db:migrate

We add the has_many and belongs_to relationship into user and api_key model respectively

# app/models/user.rb
  has_many :api_keys

# app/models/api_key.rb
  belongs_to :user

For the ApiKey class, we add a hook to before_create to generate the access token on object creation. The access_token is generated using the Ruby’s SecureRandome.hex function

# app/models/api_key.rb
class ApiKey < ActiveRecord::Base
  before_create :generate_access_token
  belongs_to :user
  
private
  def generate_access_token
    begin
      self.access_token = SecureRandom.hex
    end while self.class.exists?(access_token: access_token)
  end
end

So now when user registers to the application, we will call the user.api_keys.create! function to create the new api_key for that user

# app/controllers/sessions_controller.rb
  def create
    user = User.find_by_email(params[:email])
    if user && user.authenticate(params[:password])
      user.api_keys.create!
      session[:user_id] = user.id
      redirect_to lists_url, notice: "Logged in!"
    else
      flash.now.alert = "Invalid email or password"
      render "new"
    end
  end

Now we can rewrite the authorize function for inclusion of JSON format to use the Rails’s authenticate_or_request_with_http_token function and check on the existence of user’s api_keys with the specific access_token provided. The authenticate function does not rely on current_user variable, but instead checking the user_id param and the corresponding token to grant access.

# app/controllers/application_controller.rb
  def authorize
    case request.format
    when Mime::JSON, Mime::XML, Mime::ATOM      
      authenticate_or_request_with_http_token do |token, options|
        user = User.find(params[:user_id])
        if user
          user.api_keys.exists?(access_token: token)
        end
      end
    else  
      redirect_to signin_url, alert: "Not authorized" if current_user.nil?
    end
  end

We make a page for user to view his id and access_token. This page should be visible to only the user himself not any one else. To handle this, we define a new function in application controller called correct_user in which we check the params of user’s id, find the user based on this id and compare with the current signed in user.

# app/controllers/application_controller.rb
  def correct_user
    @user ||= User.find(params[:id])
    redirect_to(root_path) unless current_user?(@user)
  end

This function is then called by the before_filter, and applied to only the show action

# app/controllers/user_controller.rb
class UsersController < ApplicationController
  # we want to make a profile page for user to see his api_key
  before_filter :correct_user, only: :show
  
  ...

  def show
    @user = User.find(params[:id])
  end

Our show page is simply a page to display user’s information along with the access_token

# app/views/users/show.html.erb
<section class="row">
  <h1>Welcome: <%= @user.email %></h1>
  <p class="intro">Your current access_token: <%= @user.api_keys.first.access_token %></p>
  <p> Your user_id: <%= @user.id %> </p>
</section>

At this point, we are ready to expose the JSON API to the world and to build the iPhone client on the API. We’ll do that in the second part of this tutorial. Stay tuned! If you like the tutorial, follow me on Twitter @pnhoang to get the latest updates about the project.


May 25

Use CURL to manage RESTful Rails resource

I really like how powerful Rails is in terms of handling routings on the server. With only one line of code, you’re set up with 7 routes for handling with such resource. This line:

# config/routes.rb
resource :products

will define 7 routes available in your application:

$ rake routes
    products GET    /products(.:format)          products#index
             POST   /products(.:format)          products#create
 new_product GET    /products/new(.:format)      products#new
edit_product GET    /products/:id/edit(.:format) products#edit
     product GET    /products/:id(.:format)      products#show
             PUT    /products/:id(.:format)      products#update
             DELETE /products/:id(.:format)      products#destroy

To test these routes, the fastest way is to use a command line tool, CURL. In this tutorial, I will first create a new rails application, then I will use CURL to manage resources without using a browser.

Let’s first create a Rails application

$ rails new store
$ cd store

Then we use Rails scaffold generate function to be able quickly generate the complete code for our model, let’s say we have a Product model with two attributes: name and description

$ rails generate scaffold Product name:string description:text

Then we run the rake migration command to create the database tables

$ rake db:migrate

Now we should be able to see our Rails app in the server with rails server command

$ rails server

Navigating to http://localhost:3000/products we should be able to create new product, view the product listings, edit product or destroy it

Now we don’t want to use browser to do all that, we just use CURL to interact with our server’s database

  1. The first action we want to do is to add some products, we’ll have to use the new_product url to get the data for the new product. Let’s add a .json into the request url so we have the data in json.
     new_product GET    /products/new(.:format)      products#new
    
    $ curl http://localhost:3000/products/new.json
    {"created_at":null,"description":null,"id":null,"name":null,"updated_at":null}
    
  2. Now we might use this data to create a new product in the database, using the POST /products url scheme
                 POST   /products(.:format)          products#create
    
    $ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"created_at":null,"description":"Pragmatic programmers","id":null,"name":"Agile development with Rails","updated_at":null}'  http://localhost:3000/products
    
  3. Now we can verify if the product is created in the database by accessing the index route
        products GET    /products(.:format)          products#index
    
    $ curl http://localhost:3000/products.json
    
    [{"created_at":"2012-05-25T15:56:39Z","description":"Pragmatic programmers","id":1,"name":"Agile development with Rails","updated_at":"2012-05-25T15:56:39Z"}]
    
    And it’s there in the database, we already succeeded to create a new product. Notice that the result is a [] array because we are querying a list of all products.
  4. We can also view a specific product by querying its product GET route
         product GET    /products/:id(.:format)      products#show
    
    $ curl http://localhost:3000/products/1.json
    {"created_at":"2012-05-25T15:56:39Z","description":"Pragmatic programmers","id":1,"name":"Agile development with Rails","updated_at":"2012-05-25T15:56:39Z"}
    
    Here we have only one record, so it’s a hash {} with all product’s attributes.
  5. The next route we might want to test is the edit product route, we would like to change the name to “Agile development with Rails second edition”, the edit product path will be used to populate existing product into the form
    edit_product GET    /products/:id/edit(.:format) products#edit
    
    $ curl http://localhost:3000/products/1/edit.json
    
    Template is missing
    
    Missing template products/edit, application/edit with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "/Users/pnhoang/work/store/app/views"
    
    Here we have a 501 internal server error, as the default scaffold template does not generate data for edit product path. Let’s change it in the products_controller.rb file
    # app/controllers/products_controller.rb
    
      # GET /products/1/edit
      def edit
        @product = Product.find(params[:id])
            
        respond_to do |format|
          format.html # new.html.erb
          format.json { render json: @product }
        end
      end
    
    Now we can re-try
    $ curl http://localhost:3000/products/1/edit.json
    
    {"created_at":"2012-05-25T15:56:39Z","description":"Pragmatic programmers","id":1,"name":"Agile development with Rails","updated_at":"2012-05-25T15:56:39Z"}
    
    Great! We can see the existing product.
  6. In order to actually edit the product, we have to submit the PUT request to the product url. In the data submitted, I have omitted the created_at and updated_at fields, as these fields are automatically handled by Rails. We don’t have to submit those fields.
                 PUT    /products/:id(.:format)      products#update
    
    $ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X PUT -d '{"description":"Pragmatic programmers","id":1,"name":"Agile development with Rails second edition"}'  http://localhost:3000/products/1.json
    
  7. The last route that you might want to test is the Delete route. This is easy, we just need to send a DELETE request to the products/id url
                 DELETE /products/:id(.:format)      products#destroy
    
    $ curl -X DELETE http://localhost:3000/products/1
    
    
    

That’s it for now. I hope you enjoy it. Stay tuned as I will soon post a long article on building a Rails application as the backend for an iPhone app. Follow me on Twitter: @pnhoang


May 11

Install TextMate bundles for SCSS, Less, CoffeeScript

I have started working with Rails for about a month or so, and Rails comes together with a lot of new cool stuffs, such as SCSS (Sassy CSS) or Less or CoffeeScript. But as I open a Rails project in TextMate, these files are not properly formatted, only the boring black and white colors. I have just found out that we can customize TextMate to use different bundles for different languages. These bundles will make the code looks better and sometimes they support even autocomplete. 

You just need to copy the *.tmbundle file into your TextMate support folder. In my case, I have my TextMate bundles located at:

$ cd /Applications/TextMate.app/Contents/SharedSupport/Bundles/

Now suppose I want TextMate to know the format of Less, SCSS or CoffeeScript files, I just do a cloning from the proper repository on GitHub.

  • Less file: e.s. custom.css.less:
$ git clone https://github.com/appden/less.tmbundle.git 
  • CoffeeScript file: e.s. custom.js.coffeescript:
$ git clone git://github.com/jashkenas/coffee-script-tmbundle CoffeeScriptBundle.tmbundle
  • SCSS file: e.s. custom.css.scss:
$ git clone git://github.com/kuroir/SCSS.tmbundle.git "SCSS.tmbundle"
There are many more bundles that you can install depends on your need. Just try to search for them in Github with “TextMate bundle”

May 10