multiple models in Rails with a shared interface - ruby-on-rails

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.

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.

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.

Related

Using a junction table with its own relationship

I'm creating an app that has a User and a Plugin model. A user can have multiple plugins and a plugin can belong to multiple users, which I've implemented using a junction table.
class Plugin < ActiveRecord::Base
has_many :user_plugins
has_many :users, through: :user_plugins
end
class User < ActiveRecord::Base
has_many :user_plugins
has_many :plugins, through: :user_plugins
end
class UserPlugins < ActiveRecord::Base
belongs_to :user
belongs_to :plugin
end
However, I then want to store arbitrary data for each user plugin (for example, things like api keys, options etc that can differ for each plugin.).
My initial approach was to have a user_plugins_options that joined on user_plugins, but I can't seem to get this to work correctly.
class UserPluginOptions < ActiveRecord::Base
belongs_to :user_plugins
end
My question, how should I go about approaching this to best work with ActiveRecord?
I think you misnamed your class, as the table is user_plugins but the model is UserPlugin. It’s plausible you are running into issues because of this.
Agree with Alex. Why don’t you create a json field on UserPlugin called options and keep a hash of plugin specific values here.
If you must have another table, you should add a has_one :user_plugin_option to your UserPlugin

Layers of associations and descriptions on rails

I am trying to implement a resume feature and I was wondering the best practice for handling it. Lets assume a user has 2 pieces to a resume, education and work experience, and this is constant among all users. Then under each I want to save titles of things they've done (eg. Attended school at ______, worked at ________, project doing _______). Within these I want to save a description of that specific activity. What would be the best practice for implementing this?
So I need some association like: a user has_many experiences. An experience has_many titles. A title has_many descriptions. I also need to make the title of the experience is associated with the correct header (education or work experience).
I'm still pretty new to rails, and I'm sure there is a much easier and intuitive way to do this. Thanks for the help!
You can try these simple models structure for
class User < ActiveRecord::Base
has_many :locations
has_many :projects, through: experience_projects
end
class Location < ActiveRecord::Base
belongs_to :user
end
class Experience < ActiveRecord::Base
#experiences table should contain title and descriptions
belongs_to :user
has_many :projects, through: experience_projects
end
Now Join model if you do not require this intervention model you can directly use has_and_belongs_to_many
class ExperienceProject < ActiveRecord::Base
belongs_to :user
belongs_to :experience
end

Modelling Many Rails Associations

I'm trying to wrap my head around how I should model my database for a parent model with many has_one associations (20+). I have one model called House which is the parent model of all the other models:
class House < ActiveRecord::Base
has_one :kitchen
has_one :basement
has_one :garage
has_one :common_room
#... Many other child models
end
All the child models contain unique properties specific to their own class. I've thought about STI, but there isn't really any shared functionality or inputs that I can use across models. I've also thought of making one 'super model', but that doesn't really follow Rails best practices, plus it would contain over 200 columns. Is there another design pattern or structure that I can use to model this efficiently so that I can reduce database calls?
class House
has_many :rooms
Room::TYPES.each do |room_type|
has_one room_type, -> { where(room_type: room_type) }, class_name: "Room"
end
class Room
belongs_to :house
TYPES = %i/kitchen basement garage common_room etc/.freeze
end
In your migration make sure to add_index :rooms, [:type, :house_id], unique: true. Unless a house can have more than 1 type of room. If that is the case, I think a different approach is needed.
To your second question, it depends really, what type of database are you using? If its PostgreSQL you could use hstore and store those as a properties hash. Or you could serialize you db to take that as a hash. Or you could have another model that room has many of. For instance has_many :properties and make a property model that would store that information. Really depends on what else you want to do with the information
Why not using Polymorphism in Rails? It would be much simpler
class House < ActiveRecord::Base
has_many :properties, as: :property_house
end
class Kitchen < ActiveRecord::Base
belongs_to :property_house, polymorphic: true
end
class Garage < ActiveRecord::Base
belongs_to :property_house, polymorphic: true
end
For more information, go here: http://terenceponce.com/blog/2012/03/02/polymorphic-associations-in-rails-32/

Model association between Company, Employee, and department

I am working in Ruby on Rails 3. And trying to map out three models which mimic the data of a Company its employees and their respective departments.
In arrived at the following solution:
class Company < ActiveRecord::Base
has_many :departments
has_many :employees, through => :departments
end
class Department < ActiveRecord::Base
belongs_to :company
has_many :employees
has_one :department_description
end
class DepartmentDescription < ActiveRecord::Base
belongs_to :department
end
class Employee < ActiveRecord::Base
belongs_to :department
end
Is this the 'correct' way to associate these models?
I think your last response may explain why you are struggling to find a correct way to associate these models.
It seems that you see your Department merely as a join_table, and that may be due to the fact that you don't fully understand the has_many => :through construction and that it actually allows your Department to be a proper model with many attributes and methods in it, hence also a 'description' attribute.
To create a separate DepartmentDescription model is actually a waste of resource. Chad Fowler has a few good examples for :has_many => through and nested resources in his Rails Recipes... so check that out.

Modeling a Poll Feature

I'm developing a poll feature that allows users to create poll questions with options and allow other users to answer them
The answer model includes an option_id column but the two models are not related.
I have two questions:
Do my models (below) fully encapsulate what I'm trying to represent?
How would the create method for an answer controller action look? (Specifically, how to retrieve the option_id)
Note: I've never dealt with this pattern in which a model(answer) references another model (option) via option_id but the two aren't related
So far I have this:
class Question < ActiveRecord::Base
belongs_to :user
has_many :options
has_many :answers
end
class Option < ActiveRecord::Base
belongs_to :question
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
Found a tut for a mobile app doing this

Resources