Related table columns

Help for newbie please!

I have two tables: controls and programs.

controls has_many :programs Programs belongs_to :control

Controls has id, controlname Programs has, apart from it's own id, two fields ctl1_id and ctl2_id.

These represent two controls that the program relates to.

Foreign keys are set on program table columns ctl1_id and ctl2_id back to the id field on the control table.

Let's make this more explicit:

class Control < ActiveRecord::Base    has_many :programs end

class Program < ActiveRecord::Base    belongs_to :ctl1, :class_name => 'Control', :foreign_key => 'ctl1_id'    belongs_to :ctl2, :class_name => 'Control', :foreign_key => 'ctl2_id' end

So when I list the program table using

<% @programs.each do |array| %> <tr>    <td><%= array.ctl1_id%></td>    <td><%= array.ctl2_id %></td> </tr> <% end %>

...everything is fine.

Any of these: <% @programs.each do |program| %> <% @programs.each do |p| %> <% for program in @programs %>

is probably better than "array" for the block variable. (But this is a personal choice as long as you avoid keywords like "class" or "begin".)

But when I list the programs row I want to actually show the controlname from controls table rather than the ctl1_id and ctl2_id values from the programs row. For this I use the following code:-

<% @programs.each do |array| %> <tr>    <td><%= array.control.controlname %></td> </tr> <% end %>

I expect the link via the foreign keys and the models relationships to give me what I need but I am obviously missing something because I get this:-.

You have a nil object when you didn't expect it! The error occured while evaluating nil.control

Extracted source (around line #56):

53: </tr> 54: <tr> 55: 56: <%= array.control.controlname %></td>

I have checked out the cookbook application code and cant see where I am misunderstanding.

Any help gratefully received.


I can see that


<% @programs.each do |program| %>    <tr>      <td><%= program.ctl1.controlname %></td>      <td><%= program.ctl2.controlname %></td>    </tr> <% end %>

But personally, I'd rename "controlname" to just "name" since it's a column in the Control model anyway.

From this little example, it seems like you have a program with many (ok, 2) controls, but does each control really associate to more than one program? I'm just wondering whether there's another join model linking programs and controls in a many-to-many relationship.

Anyway, I suspect that you are under the mistaken assumption that the existence of foreign keys in the database have some influence on the behavior of your ActiveRecord models. Other than potentially causing inserts or deletes to fail if performed in the wrong order, your Models won't care.


Rob Biedenharn

this is clearly an example of a many-to-many relationship, an not a one-to-many relationship as you tried to do with has_many and belongs_to A Control can have one or more Programs, and a Program can belong to one or more controls.

use has_many :through or has_and_belong_to_many #Tables: controls: id, controlname

programs id, name

controls_programs control_id, program_id

the last table maps the many-to-many relationship between Controls and Programs

#Models: Control < ActiveRecord::Base   has_and_belongs_to_many :programs end

Control < ActiveRecord::Base   has_and_belongs_to_many :controls end

#controller: @programs = Program.find :all, :include => "controls"

#view <% @programs.each do |program| %>      <% program.controls.each do |control| %>    <tr>       <%= control.controlname %>    </tr>    <% end %> <% end %>

Well, just changing the code doesn't do the trick ... do you have associated the programs with the controls?

tables: #programs #controls_programs #controls id 1 program_id 1 id 2 name TestProg control_id 2 controlname TestControl

now controls_programs has an entry that reraltes Program 1 with Control 2

You achive that like this in your controller: class Program < ActionController::Base def add_control   @program = Program.find(1)   @control = Control.find(1)   @program.controls << @control end

The your programs and controls are really associated and the view code should work You can read more about that here:

also have a look at "has_many :through =>" (google will help) which is a "better" has_and_belongs_to_many ... Hope that helps

I already gave you an example in my previous post about how to add a relationship between a program and a control: #controller def add_control_to_program   @program = Program.find(params[:program_id])   @control = Control.find(params[:control_id])   @program.controls << @control end

Rails then adds the corrept mapping line into the controls_programs table You can also do it vice versa, like:

@control.porgrams << @porgram

the result is the same because of the nature of the many-to-many relationship

for more info read the API Docs about associations please, i already gave you the links in my previous post.