I messed around with Rails for a while last year, but then got busy and
had to drop it. However, I now have time again, so I’m starting to play
around with a simple database schema to model my extensive collection of
photographic material, including equipment, negatives, photographs,
etc. I’m running into an issue with using belongs_to/has_one methods.
Read on for an explanation…
I have two postgres database tables, defined as follows:
photo_dev=> \d manufacturers
Table “public.manufacturers”
Column | Type |
Modifiers
--------±-----------------------±--------------------------------------------------------------
id | integer | not null default
nextval(‘public.manufacturers_id_seq’::text)
name | character varying(255) | not null
Indexes:
“manufacturers_pkey” primary key, btree (id)
photo_dev=> \d filters
Table “public.filters”
Column | Type |
Modifiers
-----------------±-----------------------±--------------------------------------------------------
id | integer | not null default
nextval(‘public.filters_id_seq’::text)
name | character varying(255) | not null
filter_factor | numeric(2,1) | not null
manufacturer_id | integer | not null
description | character varying(50) | not null
Indexes:
“filters_pkey” primary key, btree (id)
Foreign-key constraints:
“$1” FOREIGN KEY (manufacturer_id) REFERENCES manufacturers(id) ON
DELETE CASCADE
The tables contain this test data:
photo_dev=> select * from filters;
id | name | filter_factor | manufacturer_id | description
----±-----------±--------------±----------------±------------
24 | Lee Filter | 3.0 | 5 | Deep Red
(2 rows)
photo_dev=> select * from manufacturers;
id | name
----±-----
5 | Lee
(1 row)
I’ve cobbled together this test file:
#!/usr/bin/ruby
require ‘pp’
require ‘rubygems’
require_gem ‘activerecord’
ActiveRecord::Base::establish_connection( :adapter => ‘postgresql’,
:host => ‘localhost’,
:database => ‘photo_dev’,
:username => ‘photo’,
:password => ‘photo’ )
class Manufacturer < ActiveRecord::Base
belongs_to :filter
end
class Filter < ActiveRecord::Base
has_one :manufacturer, :foreign_key => ‘id’
end
filter = Filter.find( 24 );
pp filter
print filter.manufacturer, “\n”
man = Manufacturer.find( filter.manufacturer_id );
pp man
The first problem I had was that placing this statement:
has_one :manufacturer
in the Filter class could cause invalid SQL to be generated when trying
to lookup the manufacturer. For example, I would have seen this SQL in
the stack trace:
SELECT * FROM manufacturers WHERE (manufacturers.filter_id = 24)
LIMIT 1
the wrong column name (manufacturers.filter_id) was used - I had to add
the :foreign_key => ‘id’ to fix the column name problem. Is this
normal, or have I defined the tables incorrectly? It appears that the
foreign key name assumed to also be the name of the primary key in the
child table, which breaks the assumption that all tables have a primary
key called ‘id’…
If I run the above script, I get the following output:
#<Filter:0x40559238
@attributes=
{“name”=>“Lee Filter”,
“manufacturer_id”=>“5”,
“filter_factor”=>“3.0”,
“id”=>“24”,
“description”=>“Deep Red”}>
nil
#<Manufacturer:0x40554698 @attributes={“name”=>“Lee”, “id”=>“5”}>
Calling filter.manufacturer is not finding the child record, yet if I
directly fetch the record, I can find it. What gives?
My guess is that the two problems are related, and something is borked
either in my code, or in my database definitions.
Anyone have any suggestions?
I’m running on Rails 1.0…
Cheers!
-klm.