Foto

Dec 14 2011

Sebuah Wisuda

Kebetulan pada hari Senin yang lalu saya menghadiri sebuah acara wisuda. Kebetulan juga ada kejadian kecil yang mengingatkan saya pada kejadian lainnya yang saya pikir cukup menarik juga untuk saya ceritakan di blog ini.

Sebagaimana semua prosesi wisuda, tentulah ada acara salam-salaman antara para wisudawan dengan para pimpinan universitas. Jika Anda adalah wisudawan, barangkali ini bagian yang cukup membuat deg-degan: menunggu giliran dipanggil kedepan, membayangkan Anda akhirnya mengambil selembar kertas yangg menjadi legitimasi kerja keras Anda selama beberapa tahun, atau sekedar bersalaman dengan rektor yang seumur-umur Anda kuliah tidak pernah bersalaman dengan Anda. Tapi buat orang yang menemani Anda, prosesi salaman ini membosankan setengah mati! Karena bosan itulah, setelah adik saya sang wisudawan bersalaman, saya memutuskan keluar dari gedung wisuda. Bersama saya, ikut nenek saya, “mau ke belakang”, katanya.

Saat itulah seorang juru foto menghampiri kami, membawa foto nenek dan adik saya yang rupanya ia foto saat pertama kali kami datang tadi. Berhubung saya dan keluarga sudah foto di studio foto terlebih dulu pada pagi harinya, dengan spontan reaksi awal saya adalah mengucapkan, “maaf Mas, udah foto”.

Wisuda Lainnya

Pengalaman singkat tadi mengingatkan saya pada sebuah wisuda lainnya yang saya hadiri Oktober lalu. Salah seorang sahabat karib saya menyelesaikan studi magisternya di kota Bandung. Saya pikir tak ada salahnya jika saya izin sekedar satu atau dua jam dari kantor untuk bisa mampir ke tempat wisuda sahabat tersebut. Toh tempat wisudanya juga dekat dengan kantor saya.

Ketika saya datang, waktu itu sehabis shalat Jumat, acara formal sudah selesai. Sahabat saya ini bisa keluar gedung untuk menghampiri saya. Satu hal yang saya ingat betul, teman saya ini mencari-cari juru foto. Saya tanyakan padanya, “nyari apa boy?”

“Tukang foto, tadi dia moto gw sama bokap nyokap”.

Mendengar ini, saya jadi paham arti pentingnya foto itu buat dia. Sedikit informasi buat Anda, teman saya ini orangtuanya bercerai sejak dia masih usia sekolah dasar. Saya ingat dia bilang, “ini jarang-jarang gw foto bareng bokap nyokap sekaligus”.

Saya akhirnya menemani teman tersebut cukup lama. Ia bertanya dari satu juru foto ke juru foto lainnya, mencari juru foto manakah yang tadi mengambil gambarnya. Akhir cerita, kami tidak menemukan juru foto tersebut. Teman saya meninggalkan nomor ponselnya kepada seorang juru foto yang bilang akan membantu mencarikan. Meskipun rasanya sulit mencari foto hanya berdasakan ciri-ciri fisik yang tidak begitu unik diantara ratusan wisudawan hari itu. Anda mau mencari foto dengan deskripsi “yang kurus” atau “yang gendut” pun sepertinya ada lusinan foto yang seperti itu. Lain cerita kalau teman saya ini mirip Sule, misalnya.

Soal Makna

Ternyata memang nilai sebuah benda itu sedikit banyak persoalan makna. Buat saya dan Anda, mungkin foto yang diambil oleh juru foto ecerean di sekitar acara-acara seperti wisuda itu tidak ada artinya. Dalam kasus teman saya ini, foto ini barangkali satu-satunya foto dia bersama kedua orang tuanya lengkap setelah sekian tahun. Saya bisa saja menerka-nerka seberapa penting foto ini maknanya buat dia, tapi rasanya tidak akan tepat benar menggambarkan apa yang dia rasakan.

Dalam keseharian sepertinya begitu juga, ada hal-hal yang kalau dari luar tampaknya biasa-biasa saja: sepatu yang sudah tampak butut tapi ternyata kado pertama dari kekasih, atau jam tangan tua tapi ternyata warisan dari ayah. Kadang untuk bisa membuat sesuatu bernilai, yang kita butuhkan sebenarnya bukan harga yang mahal, fitur yang lengkap, atau desain yang terbaru. Kadang yang kita perlukan hanyalah mengikat makna.

Aih, melankolis sekali!

No responses yet

Rails Nested Form with Has Many Through Association (Part 2)

Jun 07 2011

What about editing?

I create this post to answer Pierre’s question in the comment section in my previous tutorial here.

The edit part is actually not much different from the new part. Therefore, I wanted to just edit that previous post. But somehow, there is something wrong with my blog, I could not update that post. Well, I tried this and that and nothing worked while my lunch time is almost over now. I figured out, I’d better write new post even though it would only contain small addition. Let’s take a look.

First, we need to modify our edit.html.erb file to render different form:

1
2
3
4
5
6
<h1>Editing calibration</h1>

<%= render 'edit_form' %>

<%= link_to 'Show', @calibration %> |
<%= link_to 'Back', calibrations_path %>

Then, we need to create _edit_form.html.erb file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<%= form_for @calibration, :url => calibration_path(@calibration) do |f| %>
  <% if @calibration.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@calibration.errors.count, "error") %> prohibited this calibration from being saved:</h2>

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

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :tester %><br />
    <%= f.text_field :tester %>
  </div>
  <div class="field">
  <table border="1">
    <tr>
      <td>Step Name</td>
      <td>Result</td>
      <td>Note</td>
    </tr>
      <%= f.fields_for :calibration_results do |builder|  %>
        <%= render 'calibration_result_fields', :f => builder, :calibration => @calibration, :calibration_step => builder.object.calibration_step %>
      <% end %>
  </table>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Please note that the main different thing is that in this file we add the exact path to form_for and omit the part where we iterate the @calibration_steps instance to render our fields_for code.

While the controller is not changed at all. But to make sure you know what my edit method looks like, here it is:

1
2
3
  def edit
    @calibration = Calibration.find(params[:id])
  end

I guess, there we have the editing part.

3 responses so far

Bulletproof

Feb 24 2011

Idea is cheap. For whatever brilliant idea you have, for any eureka moment you celebrate, chances are among other six billion people in this world, there are others who have the same idea. Turning idea into something real is what counts. Ideas are bulletproof, indeed. But, what good is an idea if it stays idea? So, grab your keyboard and make it real. Write the code, one line at a time.

Or two lines at a time, if you have faster type speed rate.

No responses yet

Rails Nested Form with Has Many Through Association

Jan 20 2011

I tend to avoid using nested form in my rails code. If needed, I always use form_tag rather than fields_for. But in my recent project, I give a try on using nested form. It turns out that Rails’ way to build a nested form is… how to say this delicately… beautiful. So, I think, I would like to post an article on this.

As usual, I learn how to use nested form from Ryan Bates’ Railscasts and then modify it to meet my need. In this post, I particularly focus on how to use it with three models which share a has many through association among them, just like what I did in the actual project. And for your reference, you can also check the Railscasts’ episodes here and here.

The Project

In my actual project, I had to do a calibration on something (well, I can’t name what, I can’t violate the NDA). The calibration involved several steps that can be dynamically managed. And then, for every step, I had to mark whether the calibrated thing pass the step or not and I had to enable the tester to write some notes about the step conducted. In short, I translated this scheme into a three models wtih has many through association. The models are: Calibration, CalibrationStep, and CalibrationResult. Calibration has many CalibrationStep through CalibrationResult.

1. Generation

Just like any other development, let Rails kindly does our needed auto-generated codes. Of course,  we start from generating the simple app we’re going to use through this whole tutorial. I’d like to name it “calibrator”. Somehow it sounds stupid, but let it be.

1
rails new calibrator

For both Calibration and CalibrationStep, we will generate the full MVC. Here it goes the Calibration:

1
rails generate scaffold Calibration name:string tester:string

And here goes the CalibrationStep

1
rails generate scaffold CalibrationStep step_name:string step_number:integer

While for the CalibrationResult, we will only generate the model:

1
rails generate model CalibrationResult calibration_id:integer calibration_step_id:integer result:boolean note:string

And then we end this step by migrating our database.

1
rake db:migrate

2. Setting up the association

Now, let’s code. I start from the Calibration model, here is what we code:

1
2
3
4
5
class Calibration < ActiveRecord::Base
  has_many :calibration_steps, :through => :calibration_results
  has_many :calibration_results
  accepts_nested_attributes_for :calibration_results
end

You should note that it’s just ordinary association that we put in our Calibration model with a slight addition the accepts_nested_attributes_for for our nested form later on.

And then, here is our CalibrationStep model, nothing special really:

1
2
3
4
class CalibrationStep < ActiveRecord::Base
  has_many :calibrations, :through => :calibration_results
  has_many :calibration_results
end

And the last, our CalibrationResult model:

1
2
3
4
class CalibrationResult < ActiveRecord::Base
  belongs_to :calibration
  belongs_to :calibration_step
end

3. Modifying the controllers

The only controller we need to worry about is our CalibrationsController class. We should modify its show and new method. Here is our modification:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CalibrationsController < ApplicationController
  # some lines are deleted...
  def show
    @calibration = Calibration.find(params[:id])
    @calibration_steps = CalibrationStep.find(:all, :order => 'step_number ASC')

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @calibration }
    end
  end

  def new
    @calibration = Calibration.new
    @calibration_steps = CalibrationStep.find(:all, :order => 'step_number ASC')
    calibration_result = @calibration.calibration_results.build()

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @calibration }
    end
  end
  # some lines are deleted....
end

You should notice that we added a variable called calibration_result with value generated by a method called build. This build method is the key ingridients of our nested form. This method, according to Rails documentation,

returns a new object of the collection type that has been instantiated with attributes and linked to this object through the join table, but has not yet been saved.

For detailed description about this, you can look it up here with keyword collection.build().

We can leave the other controllers as they are.

4. Modifying the views

There are at least three views that we need to tweak. The first one is our app/views/calibrations/_form.html.erb file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<%= form_for(@calibration) do |f| %>
  # some lines are deleted....
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :tester %><br />
    <%= f.text_field :tester %>
  </div>
  <div class="field">
  <table border="1">
    <tr>
      <td>Step Name</td>
      <td>Result</td>
      <td>Note</td>
    </tr>
    <% @calibration_steps.each do |calibration_step| %>
      <%= f.fields_for :calibration_results do |builder|  %>
        <%= render 'calibration_result_fields', :f => builder, :calibration => @calibration, :calibration_step => calibration_step %>
      <% end %>
    <% end %>
  </table>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Then, we need to add the partial view we described in our form earlier by adding this app/views/calibrations/_calibration_result_fields.html.erb file:

1
2
3
4
5
6
7
8
9
10
11
<tr>
  <td><%=h calibration_step.step_name %></td>
  <td>
    <%= f.radio_button :result, true %>Pass
    <%= f.radio_button :result, false %>Fail
  </td>
  <td>
    <%= f.text_field :note %>
    <%= f.hidden_field :calibration_step_id, :value => calibration_step.id %>
  </td>
</tr>

And the last, we need to show the result. For this tutorial, I will just put it in my Calibration’s view that is in app/views/calibrations/show.html.erb file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<p id="notice"><%= notice %></p>

<p>
  <b>Name:</b>
  <%= @calibration.name %>
</p>

<p>
  <b>Tester:</b>
  <%= @calibration.tester %>
</p>

<table border="1">
  <tr>
    <td>Step Name</td>
    <td>Result</td>
    <td>Note</td>
  </tr>
  <% @calibration_steps.each do |calibration_step| %>
    <tr>
      <td><%= calibration_step.step_name %></td>
      <% calibration_result = CalibrationResult.find(
        :first, :conditions => {:calibration_step_id => calibration_step.id, :calibration_id => @calibration.id}) %>
      <% if !calibration_result.nil? %>
        <td>
          <% if !calibration_result.result.nil? %>
            <%= calibration_result.result==true ? "Pass" : "Fail" %>
          <% else %>
            Not yet tested
          <% end %>
        </td>
        <td><%=h calibration_result.note %></td>
      <% else %>
        <td>Not yet tested</td>
        <td>Not yet tested</td>
      <% end %>
    </tr>
  <% end %>
</table>


<%= link_to 'Edit', edit_calibration_path(@calibration) %> |
<%= link_to 'Back', calibrations_path %>

5. That’s it

That’s it. Now, you can try to add your calibration steps and then try to use the nested form in your calibration’s view. Here is a screenshot from my own trial:

the look of the nested form

7 responses so far

Get It Right

Jan 15 2011

Recently, the company I work in just released a web application. Before you close this page saying, “okay, I’m not into a marketing campaign like this”, I want to make sure that I’m not trying to promote it with this post. Of course I will, but there is more proper place and time to discuss about it than this blog post. Instead, I want to write about this funny feeling I suddenly have about the whole project. What feeling? Here we go… .

When we were a children, we fell at our first trial to walk. We failed to pronounce our own name correctly at our early stage of learning to talk. Not ended there, we had so many other failures follow later on: we stepped one or two too many in our first training to do a “lay up” in the basketball club, we fell from our bike the first time we tried to ride it, we were almost drowning in the swimming pool, and the list goes on. Unfortunately, I did not follow through on my bicycle and swimming lesson, so I can’t ride a bike and can’t swim. Yeah, it’s a shame… but I think this is not our main topic here.

My point is… I don’t think we ever get it right at the first time we attempt to do something. I don’t think anyone ever does. Yet, none of us stopped trying doing things that we now perceive as regular mundane things like walking, talking, or riding a bike (not so regular for me, though). That’s why in the end we get it right. We tried, and after many failures we finally get it right.

This childhood feeling is exactly what I feel about finally releasing our work for public consumption. For some times now, my company has struggled so bad to give a go on our previous product. We have not released it after almost one and a half year of development. Things changed when we were faced with a catastrophic event that I’m not ready to share it publicly here. In short, we changed our direction and decided to actually release something no matter how small the set of features it has. And yes, we did. We threw it for reviews to some of our friends, made required fix for these early inputs, and then a day later we “soft launched” it by posting about in the so called “social media”. In a day the web app got a hit more than this blog got in a month. Damn.

And we, of course, made mistake. There are few bugs found, and we fixed it right away. There are some things that according to people who visited should be there, and there are some things that should not be there. We take these critics and comments as input to make the web app better, and try to incorporate them to our next iteration* that is planned to be done in two weeks. And we’ll release the next version of the web app right away.

I… somehow feel so great about this. I’m definitely not saying the web app we’ve just launched will be a hit and be successful in the market. In fact, that’s not my major concern right now. It can be a flop, a hit, or another mediocre app that everyone will forget in months. But this somehow does not make me feel not enthusiastic. I’m enthusiastic about how far we can go with this one, and if it does fail in the future, how much we can learn from this. I know it sounds like a foolish thought.

But of course I’m not saying that we risk our whole fortune on this. We’re not trying to make a suicidal project, for sure. We calculate in our own way how to balance the risk and the gain we make from this one. Hopefully all the effort we put on this will worth it.

In the end, I just feel relieved about finding back my guts to not too worry about how to get things right at the first time. I’ve come to accept that nothing will be right at the first time. But please do use these words in the proper context. Don’t use it as, “yeah, don’t worry too much about our marriage, none gets everything right in the first try. So, let’s try it. If we fail… we can have a divorce, right?” I won’t hold myself responsible for divorces caused by this kind of thinking.

It’s just… when you want to make something, some work that you think worth of your time to try to make it real… don’t overthink about it. Don’t be too afraid that you will not get it right in the first attempt, because most of the time you won’t. Just start making it, and then make it available for the public to criticize it, then from that critics you make it better. I don’t guarantee you’ll make masterpieces with this approach, but in my experience so far… I feel great about how good or bad people response to what we’ve made.

Note

* iteration is a term in Agile Development Method. It describes a period of time in which developers do a full cycle of software development from analysis to deployment.

6 responses so far

7 Days After AFF Cup Final

Jan 05 2011

This idea came to my mind when I wanted to write my opinions on Indonesia’s defeat in AFF Cup Final seven days ago. A friend of mine wrote this in his Facebook wall, “sadly, that short-span nationalism will start to fade away in no time… again”. While it sounds cynical, I agree with him in some points. One of them is: we are, indeed, living in a fast paced world.

The internet has made the stream of news, information, and trend run so fast. One day I told my friends at work about some news. They replied, “heard it from Twitter yesterday”. The term “so yesterday” now actually means “so yesterday”. So I wondered, how a big news today would be in seven days later? That’s when I decided to start a series of writing titled “7 Days After”. And this is the first post on the series.

Why seven days, you may wonder. Well, I can make up some good reasons about how seven is a magic number bla bla bla. But to tell you the truth, in seven days I must have passed a weekend and a weekend is the right time to write, considering all the busyness -or “lazyness to write”, if you want to subtitute the word “busyness”- in the weekdays. That’s all my reason. Okay, enough with the chit-chat. Here we go.

Seven days after AFF Cup Final, not many things change. Malaysia won, and I guess it will flame up stupid rivalry between Indonesia and Malaysia. The rivalry has been there before, and nothing will change here.

Seven days after AFF Cup Final, some of people that were never into soccer are converted into a soccer fan. My youngest sister and one of my best friend are some real example I have faced. I guess the best way to convert people into a soccer fan is by bringing them to passionate crowd of a stadium. And Indonesians are one of the most passionate soccer fans there is.

Seven days after AFF Cup Final, I notice that the overall attitude of Indonesian soccer fans has changed. Ten years ago, early time of my experience attending live match at a stadium, I could not imagine bringing my sisters or any female to a stadium. The supporters were brutal back then. I failed to attend any of AFF Cup match this year. But, judging from responses of many who attended, the crowd relatively behaved well. Even when we finally lost in the final, the supporters still acted so supportive. Some years ago, a lose meant a chaos in the streets afterward.

Seven days after AFF Cup Final, I’m still thanking Alfred Riedl for turning our national team players into a determined unit that always fight for the ball for 90 minutes. Therefore I’m also thanking the players for their work rate and determinations in the matches. Some of cynics may say this is a way to comfort one’s self after a defeat. I don’t care. I, as a fan, do appreciate the way our national team played in AFF Cup. Of course, minus stupid lost of composure for 45 minutes in the second half of the first leg of the final. Despite that, you guys are great! Do better in Sea Games!

Bustomi, a fighter in the midfield.

Seven days after AFF Cup Final, public enemy number one of Indonesian soccer fans is still up there reigning Indonesia’s football association. Since he was convicted for corruption and then imprisoned in 2007, most of supporters called for his resignment. The guy is shamelessly persistence. But the good news is that so are the supporters. With the rise of a new independent soccer league, some of the hardcore fans turn to this independent league and actively evanglize the others to do so.

Seven Days after AFF Cup Final, nothing has changed nation wide. While others may argue that supporting a national team is an act of nationalism, I opt to oppose this notion. For me, it was pure about soccer, the support. If we did beat Malaysia in AFF Cup, it does not make Indonesians live better than Malaysians. Soccer is just a dope not yet a hope, at this state in this country. It excites us, it does. Other than that, nothing really changes in our country. Unless we can make an entire healthy industry for soccer and sports in general, only few Indonesians children will answer “soccer player” when asked “what do you want to be when you grow up?”

Seven days after AFF Cup Final, the words “Indonesia” and “GarudaFightsBack” are no longer trending topic in Twitter. In fact, despite “Justin Bieber”, I never know there is another trending topic stays for so long. I wonder what is wrong with the society, though. Justin Bieber? Come on.

Seven days after AFF Cup Final, damn it, I even missed to really post this exactly seven days after it. Whatever. I’m not changing this series to “8 Days After”.

No responses yet

What’s Up, Doc?

Dec 23 2010

If you happen to be an Indonesian and born in Indonesia, most probably when you’re a little kid you will only have three possible answers to this question: “what do you want to be when you grow up?”. And these three possible answers are “pilot”, “policeman”, and “doctor”.

When you grow up, your parents will most probably nurture you to become a doctor. I’m not really sure why parents in Indonesia tend to overlook the profession of pilot, but I’m sure most of them would not want to see their children grow up as a poor but honest policeman or as a corrupt but rich beyond meassure policeman. I hope I don’t get arrested for this.

Being a doctor is every Indonesian’s dream. If you are a male medical student or doctor, it’s a good chance that your girlfriend’s parents receive you gladly when you visit their home. If you are a female medical student or doctor, it’s more likely that guys with approximated-future-income lower than you will back off, so you’re getting the better ones. Just kidding. My point is, being doctor is understandably a very popular choice of career here in my country: doctors are well respected, well paid, and a little bit late to get married if they choose to be a specialist first before getting married. Of course we can’t forget to mention one greatest advantage of being a doctor: the virtual obligation of non doctor people to never call you without your intellectual degree: “doc”.

This sometimes puzzles me. For all I care, there are a lot of degrees and professions out there. Few of them have this kind of custom. You see, there are lawyers, engineers, and architects but I never have to call my lawyer “law”, or my fellow engineers “eng”, or the  architect that build my house “arc”. That would be weird. And it will be weird too if you think I do have a lawyer and an architect building a house for me.  I’m not that rich yet to build my own house. But I think I may need a lawyer if any doctor is offended by this post and try to sue me.

You may think I exaggerate this, that makes the  two of us. But I do try, at times, to call a doctor with just “Pak” or “Bu” (Indonesian words for “Sir” and “Ma’am”), they rarely respond back. I don’t know if in different places you can actually just call your doctor with “Sir” or “Ma’am” and they respond to you. From what I watch in tv, the Japanese have the word “sensei” to call a doctor. But that word is not exclusively for doctors, it applies also to teachers and lawyers.

Well, I often wonder, is it disrespectful for an Indonesian doctor to be called without mentioning their degree? If you happen to be a medical student reading this blog, will you oblige people to call you with “doc” when you have the degree? If you happen to be a doctor reading this, I’m just kidding doc… this is not a serious post. Don’t sue me. If you happen to be not both, guys… show some respect for people whose job is saving lives in daily basis.

Last thing, you may be asking about what makes me write this rant. Believe me, I have no problems with doctors. It’s just, everytime I have to call them “doc” I have this mental image of myself turning into some long eared creatures with grey and white hair holding a carrot:

what's up, doc?

5 responses so far

Rails 3 Authentication and Authorization with Devise and CanCan (Part 2)

Dec 16 2010

This is the second part of two posts tutorial on how to use Devise and CanCan with Rails 3. You can find the first part of this tutorial here.

Where were we?

In the previous part, we have used Devise library to create our User model in CRUD style. With what we have coded in the previous part, you should now be able to manage users and authenticate them. Now it’s time to add the roles and define what features they may access.

1. Adding the Roles

This step is pretty traditional, we can just scaffold all the MVC part for our roles. In this article, I only need one attribute that is the name of the role.

1
rails generate scaffold Role name:string

2. Making HABTM relationship between roles and users

We have to do several tasks in this step. The first thing is to manually create the migration file for the habtm table. We do it by first generating the migration file like this:

1
rails generate migration UsersHaveAndBelongToManyRoles

and then we fill the file with this code:

1
2
3
4
5
6
7
8
9
10
11
class UsersHaveAndBelongsToManyRoles < ActiveRecord::Migration
  def self.up
    create_table :roles_users, :id => false do |t|
      t.references :role, :user
    end
  end

  def self.down
    drop_table :roles_users
  end
end

And do not forget to modify our model files. This is how our role.rb looks like after we modify it:

1
2
3
class Role < ActiveRecord::Base
  has_and_belongs_to_many :users
end

And this is how our user.rb file looks like. Please be noted that we also add :role_ids in the attr_accessible and we add a method to identify the role of the respective user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User < ActiveRecord::Base
  has_and_belongs_to_many :roles
 
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable, :lockable and :timeoutable
  devise :database_authenticatable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :username, :password, :password_confirmation, :remember_me, :role_ids

  def role?(role)
    return !!self.roles.find_by_name(role.to_s.camelize)
  end
end

In the views part, we have to modify at least the _form.html.erb from our users view so that we can assign the role to the user from web interface. This is how the file users/_form.html.erb looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<%= form_for(@user) do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
        <% @user.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= f.label :email %><br />
    <%= f.text_field :email %>
  </div>
  <div class="field">
    <%= f.label :username %><br />
    <%= f.text_field :username %>
  </div>
  <% if @current_method == "new" %>
    <div class="field">
      <%= f.label :password %><br />
      <%= f.password_field :password %>
    </div>
    <div class="field">
      <%= f.label :password_confirmation %><br />
      <%= f.password_field :password_confirmation %>
    </div>
  <% end %>
  <% for role in Role.find(:all) %>
    <div>
      <%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
      <%= role.name %>
    </div>
  <% end %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Of course you can also modify your index.html.erb and show.html.erb files to show the role of the listed user(s). But I think I leave it to you to do it yourself. After all these tasks, we can run rake task db:migrate.

1
rake db:migrate

In this state, we can now add users and assign them with the roles we desire. But of course each role has not yet identified with any permission by CanCan. That’s what we’re going to do in the next step.

3. Adding ability

To use CanCan, we have to make a class that defines the permissions that are given to each role. In CanCan, this is called as “ability” and to set it up, we have to create the ability.rb file as part of our models.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Ability
  include CanCan::Ability
 
  def initialize(user)
    user ||= User.new # guest user

    if user.role? :administrator
      can :manage, :all
    elsif user.role? :operator
      can :manage, Post
    else
      can :read, :all
    end
  end
end

CanCan use a very pleasant way to describe our roles and it’s corresponding allowed features. In our code above, we use the keyword “can” and then follow it with the level of authorization we want the respective role to have and at last we end it with the name of the model. The level of authorizations that I have tried so far is :create, :read, :update, :delete, and :manage. Maybe there is a way to define another ability, you can find about it in depth in the official Github page of CanCan library here.

4. Adding authorization

Finally, in every controller that needs authorization, we add this line:

1
load_and_authorize_resource

Final Words

I think that’s it for now. I know I only have covered the basic part of using Devise and CanCan but I hope this can be helpful for anyone that just starts to learn about both libraries. I may add a working source code to this tutorial later. Meanwhile, if you have any trouble following this tutorial, you can ask me in the comment section.

6 responses so far

Random Thoughts About Time

Dec 08 2010

I don’t believe that human race will finally invent a time machine. At the very least, I believe, until I die, a time machine that can enable people to travel back and forth through time will not be available commercially just like Twitter’s timeline. How can I be so sure? Well, most of people have done some things they regret in the past. So do I. The thing is, whenever I think of time machine, I always have several certain events in my past that I want to correct, I want to undo.  To this day, I still have not undone them, so it’s a little chance that in my future I will have ever used a time machine. Or maybe, NASA will finally invent the time machine but I’m not rich enough to use it. Too bad.

I believe that we need to look back at the past, just not so often. Imagine that our life is a speeding car, the past is like the rear windows. We need to check them at times, but the main focus is the road ahead. You know, watching the rear windows can avoid you from being hit from behind, but to reach the destination you obviously need to look forward. Just please note that this analogy comes from someone who has not yet gotten his driving license.

I don’t believe we can waste time, let alone kill it. If anything, I see the time as an ignorant bastard who just walks away in steady speed. You can’t ask time to stop. You can’t ask time to wait for you while you’re tieing your shoes. The only thing you can do is to catch up and not to lose pace.

I also believe that muslims should end the debate about how to agree on certain time, certain date. You see, if we want our lunar calendar system to be credible and usable around the world, we have to have an agreement. Imagine if we are to make appointment using hijriyah calendar, “dude, where were you? I thought we would meet at 5th of Syawal”. “Oh, man, it’s 5th of Syawal now, it seems we had a different Eidul Fitri”. To all muslim scholars, please fix this issue. Oh well, I’m a day late to say this, “happy new hijriyah year!”. Maybe I’m not late afterall, maybe some muslims somewhere just celebrate the new year today.

In the end, I highly believe that it’s quite pointless to really read through these paragraphs, especially if you read this in your working time. Nah, back to work, your employer did not hire you to sit and surf the blogosphere.

3 responses so far

Hope

Nov 30 2010

Somehow, I need a motivational speech like this now.

To be hopeful in bad times is not just foolishly romantic. It is based on the fact that human history is a history not only of cruelty, but also of compassion, sacrifice, courage, kindness.

What we choose to emphasize in this complex history will determine our lives. If we see only the worst, it destroys our capacity to do something. If we remember those times and places—and there are so many—where people have behaved magnificently, this gives us the energy to act, and at least the possibility of sending this spinning top of a world in a different direction.

And if we do act, in however small a way, we don’t have to wait for some grand utopian future. The future is an infinite succession of presents, and to live now as we think human beings should live, in defiance of all that is bad around us, is itself a marvelous victory.

-Howard Zinn-

No responses yet

Older posts »