20seven

Devigner blog about development and design

Has_many :through & Lookup Tables

Rails 1.0 is great, but 1.1 additions have made web dev even easier. One of the nice new features of 1.1 is has_many :through. A nice tutorial of hm:t can be found at blog.hasmanythrough.com (Part 1 & Part 2).

What i would like to cover is how to use a lookup (association/relationship) table on top of the hm:t feature.

For example, I have a table of `users` and a table of `reports`. Since multiple users can contribute to the report, we add a third table `contributions`.

class User < ActiveRecord::Base
  has_many :contributions, :dependent => true
  has_many :reports, :through => :contributions
end

class Report < ActiveRecord::Base
  has_many :contributions, :dependent => true
  has_many :users, :through => :contributions
end

class Contributions < ActiveRecord::Base
  belongs_to :user
  belongs_to :report
end

Looks just like the example I linked to you say & you’re right! But, that’s not all. My customer now wants to categorize the reports. So we make a simple lookup table called `report_types`. It has `id`, `report_type_name`, `created_on`, & `updated_on` fields. We then add the field `report_type_id` to the `reports` table. Next we generate a model for `report_types` & then add


has_many :reports

to the ReportType class (report_type.rb) and we add

belongs_to :report_type

to the Report class we previously created.

If you have more than one lookup table just repeat the above procedure for adding more lookup tables.

So we now have everything setup properly, but how do we output the value from the lookup table? Quite easily in fact. We’ll look at two examples. First we are going to display all report contributions for all users. So we generate a new controller called `reports`. Then we create an index method.

class ReportController < ApplicationController
  def index
     @reports = Report.find_all
  end
end

we then add another method `by_user` to the `Report` controller which will display reports contributed to by a single user.

def index
   @writer = User.find(@params["id"])
       # assume the id is passed as a parameter
   @reports = @writer.reports.find_all
end

Now that we gotten our data out of the database, how do i display the actual report type and not the id you ask? It’s as simple as adding the line



  1. inside a loop such as:
  2. @reports.each do |userreport|
    <%= userreport.report_type.report_type_name %>

  3. end of loop

anywhere in your rhtml file. The important thing is to remember to use the association that you put in the belongs_to statement and not the class name.
<@instancevar>.<association>.<association_field>

And there you have it. Lookup table data while using hm:t. Have fun coding!