Forum: Ruby on Rails has_one not working as expected?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
F1ff70748b4868227ad439e2dce31770?d=identicon&s=25 Ken Miller (Guest)
on 2006-01-22 04:43
(Received via mailing list)
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.
Af93ba6b6b59f22a8f37e8de5702ef98?d=identicon&s=25 Bob Silva (Guest)
on 2006-01-22 05:25
(Received via mailing list)
I'm using the supplied scaffold.css file and in my layout I have a
transitional doctype:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitiona...

Using this doctype and scaffold.css, when error_messages_for() is used,
the
styles don't get applied. I believe it is due to the css using
#ErrorExplanaion and the actual id/class names are errorExplanation.
Note
the capitalization of the 'E' in error. Fixing the css allowed the
styles to
be applied to the default output of error_messages_for.

Should this be fixed?


Thanks.

Bob Silva
Bc4ed9c8620ac84e4024caf1e4d5d0f5?d=identicon&s=25 Erik Rothwell (Guest)
on 2006-01-22 06:56
(Received via mailing list)
On Sat, Jan 21, 2006 at 08:39:59PM -0700, Ken Miller wrote:
> Calling filter.manufacturer is not finding the child record, yet if I
> directly fetch the record, I can find it.  What gives?

Your associations are reversed.

Instead of:

    Filter
      has_one :manufacturer, ...

    Manufacturer
      belongs_to :filter

Use:

    Filter
      belongs_to :manufacturer

    Manufacturer
      has_one :filter (or, has_many :filters)

The belongs_to association (whether in a one-to-one or one-to-many
relationship) always applies to the class whose table has the foreign
key referencing the other. In your case, your filters table has a FK
referencing the manufacturer. Ergo, Filter belongs_to Manufacturer. See
the API docs[1] for more examples.

Erik.

[1]
http://ar.rubyonrails.org/classes/ActiveRecord/Ass...
59de94a56fd2c198f33d9515d1c05961?d=identicon&s=25 Tom Mornini (Guest)
on 2006-01-22 08:14
(Received via mailing list)
Wow!

My scaffolding derived forms look a *lot* better now.

Thanks!

I think you need to file a bug report for this...

--
-- Tom Mornini
Af93ba6b6b59f22a8f37e8de5702ef98?d=identicon&s=25 Bob Silva (Guest)
on 2006-01-22 08:23
(Received via mailing list)
Bug report submitted.
Be091342d3ab7f08e046310d601f213d?d=identicon&s=25 baz Scott (Guest)
on 2006-01-27 13:37
Thank you Bob, I spent hours trying to figure this out today and I got
it down to commenting out the doctype made errors work - but that just
confused me more, simple capitalisation, why is it always the simple
things that hurt the most?

Bob Silva wrote:
> I'm using the supplied scaffold.css file and in my layout I have a
> transitional doctype:
>
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitiona...
>
> Using this doctype and scaffold.css, when error_messages_for() is used,
> the
> styles don't get applied. I believe it is due to the css using
> #ErrorExplanaion and the actual id/class names are errorExplanation.
> Note
> the capitalization of the 'E' in error. Fixing the css allowed the
> styles to
> be applied to the default output of error_messages_for.
>
> Should this be fixed?
>
>
> Thanks.
>
> Bob Silva
Ad7805c9fcc1f13efc6ed11251a6c4d2?d=identicon&s=25 Alex Young (Guest)
on 2006-01-27 13:43
(Received via mailing list)
baz Scott wrote:
> Thank you Bob, I spent hours trying to figure this out today and I got
> it down to commenting out the doctype made errors work - but that just
> confused me more, simple capitalisation, why is it always the simple
> things that hurt the most?
>
Because that's when you kick yourself the hardest :-)
This topic is locked and can not be replied to.