I’m trying to combine has_many :through and polymorphic associations.
I’ve got it working one way but the other way it fails.
Here’s the domain I’m trying to model:
I’ve got a number of different authorable objects including
Activities and Simulations. Each authorable object can be related to
0 or more Subjects such as Math, Science, etc. I’d like to be able
ask the following types of questions:
- list all activities that have the subject Math
- list all authorable objects hat have the subject Science
- list all the subjects for an Activity
- list all the subjects for a Simulation
I used this as a reference: http://dev.rubyonrails.org/ticket/7143:
[PATCH] allow polymorphic :source for has_many :through
I’ve tried this on edge Rails (rev 6786) and v1.2.3.
Here are my ActiveRecord models:
class Activity < ActiveRecord::Base
has_many :subjectings
has_many :activity_subjects, :through => :subjectings, :source =>
:subjectable, :source_type => ‘Activity’
end
class Simulation < ActiveRecord::Base
has_many :subjectings
has_many :activity_subjects, :through => :subjectings, :source =>
:subjectable, :source_type => ‘Simulation’
end
class Subject < ActiveRecord::Base
has_many :subjectings
has_many :subject_activities, :through => :subjectings, :source =>
:subjectable, :source_type => ‘Activity’
has_many :subject_simulations, :through => :subjectings, :source =>
:subjectable, :source_type => ‘Simulation’
end
class Subjecting < ActiveRecord::Base
belongs_to :subject
belongs_to :subjectable, :polymorphic => true
end
This works well from the Subject side of things but there is
something wrong from the Activity or Simulation side of the
association.
Here’s my schema:
create_table “activities”, :force => true do |t|
t.column “name”, :string
end
create_table “simulations”, :force => true do |t|
t.column “name”, :string
end
create_table “subjectings”, :force => true do |t|
t.column “subject_id”, :integer
t.column “subjectable_id”, :integer
t.column “subjectable_type”, :string
end
create_table “subjects”, :force => true do |t|
t.column “name”, :string
end
Here’s the testing in script/console:
math.subject_activities.push(activity_fractions, activity_decimals)
math.subject_simulations.push(simulation_ratios, simulation_base10)
science.subject_activities.push(activity_density, activity_batteries)
science.subject_simulations.push(simulation_buoyancy, simulation_circuits)
I can get the activities that have the subject “Math”:
math.subject_activities.each { |a| puts “#{a.id}: #{a.name}” }; nil
1: Fractions
2: Decimals
I can also get the simulations that have the subject “Math”:
math.subject_simulations.each { |s| puts “#{s.id}: #{s.name}” }; nil
1: Interactive Ratios
2: Powers of Ten
Or I can get all the authorable objects that have the subject “Math”:
math.subjectings.each { |s| puts “#{s.subjectable.id}:
#{s.subjectable_type}, name: #{s.subjectable.name}, class:
#{s.subjectable.class}” }; nil
1: Activity, name: Fractions, class: Activity
2: Activity, name: Decimals, class: Activity
1: Simulation, name: Interactive Ratios, class: Simulation
2: Simulation, name: Powers of Ten, class: Simulation
But trying to get the subjects for an activity fails:
activity_fractions.activity_subjects
ActiveRecord::StatementInvalid: Mysql::Error: #42S22Unknown column
‘subjectings.activity_id’ in ‘where clause’: SELECT activities.* FROM
activities INNER JOIN subjectings ON activities.id =
subjectings.subjectable_id AND subjectings.subjectable_type =
‘Activity’ WHERE ((subjectings.activity_id = 1))
Thanks for any pointers.