"has_two" model relationship with polymorphic model?

122 views Asked by At

I have a polymorphic PLACE model like this:

class Place < ActiveRecord::Base
  belongs_to :placeable, polymorphic: :true
...

So, for example, in my Lodging model I have something like:

class Lodging < ActiveRecord::Base
has_one :place, as: :placeable, dependent: :destroy
...

And they work as expected. The point is that now I want to create a CarRental model and this model has TWO places, on is the pick-up place and the other one is the drop-off place.

So I wrote:

class Transportation < ActiveRecord::Base
has_one :start_place, as: :placeable, dependent: :destroy
has_one :end_place, as: :placeable, dependent: :destroy

And of course that does not work. Any insights on how to do that?

EDIT 1: IF I DO LIKE

class Transportation < ActiveRecord::Base
has_one :start_place, class_name: 'Place', as: :placeable, dependent: :destroy
has_one :end_place, class_name: 'Place', as: :placeable, dependent: :destroy

It works! But why? Where is the start or end information saved?

** EDIT 2: NOPE, IT DOES NOT WORK ** It does not work... =(

2

There are 2 answers

5
D-side On BEST ANSWER

I guess, associations spitted out errors before because of the unknown classes. has_one :start_place by default assumes you mean a class StartPlace that doesn't exist. It singularizes the term (as best as it can) and converts it to CamelCase. Once you've specified that you mean Place, it's clear.

You should be adding a new column anyways.Let's try single table inheritance (STI). Add a column type of type string to your places table:

rails generate migration AddTypeToPlaces type:string

...make sure it does what it says, then migrate and create new models like so:

rails generate model StartPlace --no-migration --parent=Place
rails generate model EndPlace   --no-migration --parent=Place

Note: they don't get a dedicated table and inherit from Place, not ActiveRecord::Base. It should generate two empty classes, that's fine, they inherit things from Place.

...then revert your associations to what didn't work a while ago:

has_one :start_place, as: :placeable, dependent: :destroy
has_one :end_place,   as: :placeable, dependent: :destroy

...and they should work now, because StartPlace is defined as

Place with type equal to "StartPlace"

...same with EndPlace with corresponding type.

I described this quite some time ago for a similar case.

4
Max Williams On

Your schema doesn't make sense to me - that places belong to lodgings etc. Surely there's a fixed number of places, and then they can have a number of different things in them? In your schema the same place could be in the database lots of times which seems wrong. I don't think that polymorphic associations are the way to go here either.

I would model this like so:

class Place
  has_many :lodgings
  has_many :starting_transportations, :class_name => "Transportation", :as => :start_place
  has_many :ending_transportations, :class_name => "Transportation", :as => :end_place

class Lodging
  belongs_to :place #using lodgings.place_id

class Transportation
  belongs_to :start_place, :class_name => "Place" #via transportations.start_place_id
  belongs_to :end_place, :class_name => "Place" #via transportations.end_place_id

btw, i think "Location" is a better name than "Place" for physical locations in the real world. "Place" sounds too vague.