Single Table Inheritance & ActiveRecord Associations - ruby-on-rails

I'm attempting to have a parent model that other models inherit from, and a secondary class that has associations with the children from the first model. Here's what I have so far...
I used the first command to create the parent model.
rails g model Person name:string age:integer height:float
I then set up Person as the parent class, and two children class which inherit from it as seen below.
class Person < ActiveRecord::Base
self.abstract_class = true
end
class Driver < Person
self.table_name = "Driver"
belongs_to :vehicle
end
class Passenger < Person
self.table_name = "Passenger"
belongs_to :vehicle
end
I also set up a Vehicle class to use in an association with the Driver and Passenger children classes.
rails g model Vehicle color:string capacity:integer
class Vehicle < ActiveRecord::Base
has_one :driver
has_many :passengers
end
However, if I use the rails console and attempt to create a new instance Driver or Passenger, using Driver.new or Passenger.new, I encounter an PostgreSQL error.
For reasons which I cannot figure out, Rails is writing SQL statements to query on a Driver or Passenger table. However, it is my understanding that only one Person table is made and has a type attribute that is used for queries.
If anyone can offer some guidance here, I'd be very appreciative.
Thanks

Since it seems you're trying to use the common table persons for both Driver and Passenger, you don't need the abstract_class declaration, or the table_name declarations in either of the sub classes. Per the rails documentation, these options would be used when you want classes to inherit behavior from their parent, without the parent itself having a table.
The snippet below should work fine.
class Person < ActiveRecord::Base
end
class Driver < Person
belongs_to :vehicle
end
class Passenger < Person
belongs_to :vehicle
end

Related

How does attribute class_name effect my model?

In my web dev class we were given the following code:
class User < ActiveRecord::Base
has_many :shouts
has_many :followed_user_relationships, class_name: "FollowingRelationship"
has_many :followed_users, through: :followed_user_relationships
def follow(other_user)
followed_users << other_user
end
end
I understand everything except what class_name does. Does it add information to the model relationship somehow or does it just make this relationship an alias of that class name? I checked out the documentations and it seemed pretty worthless for someone new to rails.
Rails needs to know which class to instantiate for an association. It does this by guessing based on the association name, but it can only do this when your class and association are named predictably. Specifically, it uses String#classify to turn an association name into a class name. classify converts from underscore case to camel case, and singularizes the word:
"some_kind_of_records".classify => "SomeKindOfRecord"
In your particular case, your association name and class name aren't related this way.
:followed_user_relationships would cause Rails to look for a class called FollowedUserRelationship, which isn't the right class, FollowingRelationship.
Because you've deviated slightly from this convention, you have to explicitly tell Rails the name of the class involved. That's all class_name does. It tells Rails the name of the class to use, when Rails isn't able to guess correctly.
Consider a simpler example:
class User < ActiveRecord::Base
end
class Post < ActiveRecord::Base
belongs_to :author, class_name: 'User'
end
How could Rails know that a Post is associated with a User, if all we had written was belongs_to :author?

Inheriting off an active record model in Ruby on Rails

I was hoping I could inherit off an activerecord model, and use the subclass as I could the parent class. This does not appear to be the case, the AR relationships do not appear to work for the subclass.
class Manager < User
belongs_to :shop
end
class Shop < ActiveRecord::Base
has_many :managers
end
class PremiumShop < Shop
end
and
#premium_shop = manager.shop # Finds the shop.
#premium_shop = manager.premium_shop # Does not find the shop, NilClass:Class error
Is it possible to make this work?
The shop method exists for some instance of the Manager class because of the association you defined through the belongs_to. You have no premium_shop method defined on your Manager model, thus the NilClass error.
If you want to define such an association for the PremiumShop class, you must explicitly specify this.
belongs_to :premium_shop, class_name: "PremiumShop", foreign_key: :shop_id
Depending on your needs, you might also consider researching "rails single table inheritance".

rails n:m how to have rails associations when the db table names are different

I have a project which does not follow the rails nameing conventions, because it is not possible for a special case.
Scenario:
I have a model called Foo, and the database table for this model called example_foos.
I have a model called Bar, and the database table for this model called example_bars.
I want to create a n:m association between these two models with a model FooBar. Database table name for this model is ExampleFooExampleBars.
Now my question..how can I specify the has_many throught association in the models?
If I do it like normal, I get errors because the model and table names are different..
The associations are referring to the class names, so:
class Foo < ActiveRecord::Base
set_table_name 'example_foos'
has_many :bars
end
class Bar < ActiveRecord::Base
set_table_name 'example_bars'
belongs_to :foo
end
If your model and table has different name you can
class Foo <ActiveRecord::Base
set_table_name "example_foos"
end
rest of association as per rails convention way

Issue with polymorphic association in a subclass

I have some issues with the polymorphic associations in Rails 3. My model looks like this:
class Address < ActiveRecord::Base
belongs_to :contactable, :polymorphic => true
end
class OrganisationUnit < ActiveRecord::Base
# some other associations
end
# Subclass of OrganisationUnit
class Company < OrganisationUnit
has_one :address, :as => :contactable
end
Now, when I want to get the Address of a Company, Rails generates the following SQL-Query:
SELECT `addresses`.* FROM `addresses` WHERE (`addresses`.contactable_id = 1021 AND `addresses`.contactable_type = 'OrganisationUnit') LIMIT 1
In my opinion it's wrong, because the contactable_type should be "Company".
Is there any way I can fix this or tell rails that OrganisationUnit is just an abstract base class?
The is an expected behavior. When you link a STI table to a polymorphic association, Rails stores the base class name rather than the inherited class names. The STI type conversion happens after the object lookup by id.

Rails transparent child relationship

I have a polymorphic relationship, and I would like the child (polymorph?) to be completely transparent. The setup is generic:
class ScheduledEvent < ActiveRecord::Base
belongs_to :scheduleable, polymorphic:true
#has column names like #starts_at, #ends_at
end
class AppointmentTypeOne < ActiveRecord::Base
has_one :scheduled_event, :as=>:scheduleable, :dependent=>:destroy
end
class AppointmentTypeTwo < ActiveRecord::Base
has_one :scheduled_event, :as=>:scheduleable, :dependent=>:destroy
end
I would like to be able to treat AppointmentTypeOne and AppointmentTypeTwo as if THEY had the #starts_at and #ends_at table columns.
Method-wise it's very easy to add #starts_at, #starts_at=, etc to my AppointmentX classes, and refere back to ScheduledEvent. But how can I setup so that the relationship is transparent to ActiveRelation also? Letting me do something like:
AppointmentTypeOne.where('starts_at IS NOT NULL')
(not having to join or include :scheduled_event)
It sounds like you want to use Single Table Inheritance, not a has_one association. That will allow you to create subclasses of ScheduledEvent for each appointment type:
class ScheduledEvent < ActiveRecord::Base
end
class AppointmentTypeOne < ScheduledEvent
end
class AppointmentTypeTwo < ScheduledEvent
end
Basically, you add a type column to your scheduled_events table, and rails takes care of the rest.
This forum post covers all of the details: http://railsforum.com/viewtopic.php?id=3815

Resources