In my project I need User to be able to both “create/own” its own objects and “track” (or “follow”) objects created by other users. Here is my approach:
class User < ActiveRecord::Base
has_many :widgets
has_many :gadgets
has_many :nuggets
has_many :tracks
has_many :tracked_widgets, :as => :trackable, :trackable_type => "Widget"
has_many :tracked_gadgets, :as => :trackable, :trackable_type => "Gadget"
has_many :tracked_nuggets, :as => :trackable, :trackable_type => "Nugget"
end
class Track < ActiveRecord::Base
belongs_to :trackable, polymorphic: true
belongs_to :user
end
class Widget < ActiveRecord::Base # Gadget and Nugget classes are the same
has_many :tracks, :as => :trackable
end
The schema for the tracks table:
create_table "tracks", :force => true do |t|
t.integer "user_id"
t.integer "trackable_id"
t.string "trackable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "tracks", ["trackable_id", "user_id"], :name => "index_tracks_on_trackable_id_and_user_id"
With this implementation I get the following error:
Unknown key: trackable_type (ArgumentError)
Looking at the schema, it’s obvious that I don’t have :trackable_type set up as an index, so the error message makes sense. However, in the examples I’ve seen that demonstrate polymorphic relationships, I’ve never seen the ______able_type field set up as an index. This makes me wonder if I’m missing something basic here. I have these questions:
- Have I somehow incorrectly set up the
has_manyand:as => :trackablerelationships? - If not, is there any issue using a
stringfield as anindex? - If the answer is simply to add the
:trackable_typefield as an index, what is the best way to do this after the fact? Add a new migration that creates the:trackable_typeindex?
I finally figured out how to make the polymorphic association work for this case. Not sure I understand why, but the
:asoption forhas_manyis not used in some polymorphic cases. Instead you must use a standard:throughoption and then reestablish the polymorphism with the:sourceand:source_typeoptions.In my example above, the
has_manystatements in theUsermodel the needed to be formatted as follows:Hopes this helps anyone trying to address a similar situation.