views:

46

answers:

2

I'm not sure of the best structure for a particular situation in Rails. We have several types of workshops. The administration of the workshops is the same regardless of workshop type, so the data for the workshops is in a single model. We collect feedback from participants about the workshops, and the questionnaire is different for each type of workshop. I want to access the feedback about the workshop from the workshop model, but the class of the associated model will depend on the type of workshop. If I was doing this in something other than Rails, I would set up an abstract class for WorkshopFeedback, and then have subclasses for each type of workshop: WorkshopFeedbackOne, WorkshopFeedbackTwo, WorkshopFeedbackThree. I'm unsure how to best handle this with Rails.

I currently have:

class Workshop < ActiveRecord::Base
  has_many :workshop_feedbacks
end

class Feedback < ActiveRecord::Base
  belongs_to :workshop
  has_many :feedback_ones
  has_many :feedback_twos
  has_many :feedback_threes
end

class FeedbackOne < ActiveRecord::Base
  belongs_to :feedback
end

class FeedbackTwo < ActiveRecord::Base
  belongs_to :feedback
end

class FeedbackThree < ActiveRecord::Base
  belongs_to :feedback
end

This doesn't seem like to the cleanest way to access the feedback from the workshop model, as accessing the correct feedback will require logic investigating the Workshop type and then choosing, for instance, @workshop.feedback.feedback_one.

Is there a better way to handle this situation? Would it be better to use a polymorphic association for feedback? Or maybe using a Module or Mixin for the shared Feedback interface?

Note: I am avoiding using Single Table Inheritance here because the FeedbackOne, FeedbackTwo, FeedbackThree models do not share much common data, so I would end up with a large sparsely populated table with STI.

A: 

You can subclass your models, like so:

class Workshop < ActiveRecord::Base
  has_many :feedback_ones
  has_many :feedback_twos
  has_many :feedback_threes
  #has_many :feedbacks # This MIGHT work, but is untested.  I'm not at a dev setup to try.
end

class Feedback < ActiveRecord::Base
  belongs_to :workshop
  has_many :feedback_ones
  has_many :feedback_twos
  has_many :feedback_threes
end

class FeedbackOne < Feedback
  belongs_to :feedback
end

class FeedbackTwo < Feedback
  belongs_to :feedback
end

class FeedbackThree < Feedback
  belongs_to :feedback
end

This is likely a better solution, and is cleaner. Your Feedback table needs to have a type column, which it uses to use one table for multiple classes. This blog post gives a good basic introduction to the concept of Single Table Inheritance.

Mike Trpcic
I should have noted in my original post that I don't want to use STI because the different feedbacks do not share many fields, so I'd end up with a large sparsely populated table.
Del F
+1  A: 

I think the best solution is create an abstract class Workshop, and 3 subclasses Workshop1, Workshop2 and Workshop3.

Hence, each will have its set of feedbacks, Feedback1 to Workshop1, Feedback2 to Workshop2, ...

You can change the declaration in the subclasses as follows:

class Workshop1 < Workshop
  has_many :feedbacks, :class_name => "Feedback1"
end

class Feedback1 < ActiveRecord::Base
  belongs_to :workshop, :class_name => "Workshop1"
end

And in your application can use workshop.feedbacks and and feedback.workshop no matter what class the instance of the Workshop or Feedback belongs.

EDIT: You have three types of workshop with information in common, but each workshop has a specific kind of feedback. So it's bestter to use STI for Workshop, and not for Feedback.

nanda