Forum: Ruby on Rails belongs_to and lookup tables

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.
34f5b045aec62235c17458650ea75353?d=identicon&s=25 Steve Koppelman (hatless)
on 2006-04-07 17:30
I have two classes, Listing and Warranty. A Listing (think of it as a
product) may or may not have a Warranty from a lookup table.

When I want the Warranty.company for a given Listing I want to say the
following:

@listing = Listing.find(4)
@company = @listing.warranty.company

In order to do that I did the following:

  class Listing < ActiveRecord::Base
    belongs_to :warranty
  end

and of course my Listing table has a warranty_id column.

This feels wrong. For one thing, it implies a parent-child relationship
and implies that any Listings with a given Warranty can/should be
deleted when a Warranty is deleted. Secondly, when I *do* delete a
Warranty, my Listing's warranty_id still points to the deleted record's
ID, when it should instead be set to nil.

Is there a more appropriate way to express the relationship between a
class and a lookup table?
91eb76a77125229d36bf104c17c6570f?d=identicon&s=25 James Adams (nitr0z)
on 2006-04-07 17:50
I believe that (depending on your DBMS) what having an "ON DELETE SET
NULL" in the foreign key specification of the Listing table schema
should allow your DBMS to take care of this. This is of course not a
Rails solution.

A raisl solution could use the "on_delete" hook (if i'm not making it
up, im still quite new to Rails myself), and do something like:

def on_delete
  self.listings.each do { |listing|
    listing.warranty_id = null
  }
end

There may of course be a way to do this to all the objects at once
without using a block but liek I said I am new.

Hope these ideas can help you.

James Adams
0091f92762685860109bbcb02edfdf27?d=identicon&s=25 Alain Ravet (Guest)
on 2006-04-07 17:53
(Received via mailing list)
Steve
    >   class Listing < ActiveRecord::Base
    >     belongs_to :warranty
    > and of course my Listing table has a warranty_id column.
>
> This feels wrong.


When you read 'belongs_to', think 'references', 'points_to'. It won't
feel wrong anymore.

Alain
34f5b045aec62235c17458650ea75353?d=identicon&s=25 Steve Koppelman (hatless)
on 2006-04-07 20:54
Thanks. The latter sounds close to a sensible approach, though the
callback I need is before_destroy and after setting the property to nil
it needed a save().

I'll stick with this unless a better answer comes up regarding my
discomfort with using belongs_to for a relationship where I absolutely
don't ever want a cascading delete to be implied. IMO there really
should be separate associations like "refers_to" and "referenced_by" to
express the needs of a lookup table, even if all they essentially do is
(1) override :dependent to return false at all times and (2) on deletion
of a lookup table entry, nil out the fields in referring tables that
pointed to the deleted entry.

Here's the relevant code I went with. It appears to work:

in listing.rb:

  class Listing < ActiveRecord::Base
    belongs_to :warranty
  end


in warranty.rb:

  class Warranty < ActiveRecord::Base
    has_many :listings

    before_destroy :disassociate_listings

    private
      def disassociate_listings
        self.listings.each { |listing|
          listing.warranty_id = nil
          listing.save
        }
      end
  end

James Adams wrote:
> I believe that (depending on your DBMS) what having an "ON DELETE SET
> NULL" in the foreign key specification of the Listing table schema
> should allow your DBMS to take care of this. This is of course not a
> Rails solution.
>
> A raisl solution could use the "on_delete" hook (if i'm not making it
> up, im still quite new to Rails myself), and do something like:
>
> def on_delete
>   self.listings.each do { |listing|
>     listing.warranty_id = null
>   }
> end
>
> There may of course be a way to do this to all the objects at once
> without using a block but liek I said I am new.
>
> Hope these ideas can help you.
>
> James Adams
34f5b045aec62235c17458650ea75353?d=identicon&s=25 Steve Koppelman (hatless)
on 2006-04-07 20:59
It's not the name that makes it feel wrong. It's the secondary behaviors
those terms imply that makes it feel wrong. "references" and "points_to"
wouldn't imply that "child" records could be deleted safely like
"belongs_to/has_many" does. ;)

Alain Ravet wrote:
> Steve
>     >   class Listing < ActiveRecord::Base
>     >     belongs_to :warranty
>     > and of course my Listing table has a warranty_id column.
>>
>> This feels wrong.
>
>
> When you read 'belongs_to', think 'references', 'points_to'. It won't
> feel wrong anymore.
>
> Alain
This topic is locked and can not be replied to.