Rails STI design issue - ruby-on-rails

I am working a side project where a user can have multiple clients. Those client can be of type Person or Business.
I was leaning toward the idea to using STI but I am not sure whether this is the right way to go since my models will not share the same attributes.
For instance a Business has a legal_form where a Person might have a marital_status.
Is it ok to use STI in this particular case or (2nd question) is there any way to allow rails to use separate tables for each types.

STI is like inheritance in ruby. You can use it if you have parent and children and they share a lot of attributes and data. If Person and Business share a lot you can use it. Otherwise I'd recommend you use Polymorphic Associations
A slightly more advanced twist on associations is the polymorphic
association. With polymorphic associations, a model can belong to more
than one other model, on a single association. For example, you might
have a picture model that belongs to either an employee model or a
product model. Here's how this could be declared:
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
class Employee < ActiveRecord::Base
has_many :pictures, as: :imageable
end
class Product < ActiveRecord::Base
has_many :pictures, as: :imageable
end
I don't really like STI and I'd recommend you try to use Polymorphic Associations.
A common problem with STI
A common problem with STI is that, over time, more types get added to
that table, and it grows more and more columns, and the records in the
table have less and less in common with one another. Each type of
record uses some subset of the table’s columns, and none uses all of
them, so you end up with a very sparsely populated table. Those types
create costs for one another: when you query for articles, you must
remember to filter out all the other types of values and to only
select columns relevant to articles, or else pay a huge performance
cost. You reproduce a lot of work the database would do for you, if
you only had each data type in its own table.

Assuming I would go for the polymorphic association would this be correct
class Client < ActiveRecord::Base
belongs_to :cliental, polymorphic: true
end
class Business < ActionRecord::Base
# Here I am using has_one because I do not want to have duplicates
has_one :client, as: :cliental
end
class Person < ActionRecord::Base
# Here I am using has_one because I do not want to have duplicates
has_one :client, as: :cliental
end
And later I would like to do the following
class User < ActiveRecord::Base
has_many clients
has_many businesses, through: :client
has_many people, through: :client
end

Related

Rails associations has_many through instead of HABTM

I'm fairly new to rails and ActiveRecord and I'm trying to find the correct way to model my data.
I am building an application that let's swim instructors put together a class plan that shows what skills they will be teaching their class and what activities they will use to teach each skill. A Plan can contain many Skills and each Skill can have many Activities associated with it.
On the Plan form there is a widget for the skill-activity combination. In it, user should be able to select a Skill from a dropdown and for the selected skill select multiple activities from a list. This widget can repeat any number of times on the form.
My current model:
Class Plan
has_many :plan_activities
end
Class PlanActivities
belongs_to :plan
belongs_to :skill
has_and_belongs_to_many :activities
end
Class Skill
end
Class Activity
end
Is this model correct? My problem with it is that accepts_nested_attribtues_for does not work for HABTM associations. I've read that I can replace it with has_many through:, but that would mean adding yet another join model to the picture. It just seems a little too ugly. Is there a better way to do this?
EDIT:
My Skills and Activities are in list form and I should be able to include the same skill and/or activity on multiple plans.
Your model is very close. One improvement here would be to completely remove the PlanActivities model. Just have the associations directly on the plan. At this point I don't think the extra model is justified. We have a pretty basic pyramid structure here. At the top is plan with many skills, Each skill has many activities, so a simpler model would look like:
class Plan
has_many :plan_skills
has_many :activities, through: :plan_skills
end
class Skill
has_many :activities, through: plan_skills
has_many :plan_skills
end
class PlanSkill
belongs_to :plan
belongs_to :skill
has_many :activities
end
class Activity
belongs_to :plan_skill
end
The join model is an option but not entirely necessary here. Plan.activities will make the needed join table for you.

Rails Active Record multiple associations

I have a Rails app using Postgres and Active Record, and can't fathom the most efficient Associations between my models.
I have a Model called Article. Article needs to have a Format and 2/3 Genres.
I need articles to be able to be listed by format i.e. http://myapp.com/format/format-id/article-id
I also need articles to be listed by genre, so: myapp.com/genre/genre-name/article-id
I was thinking the Genres and Formats would be models themselves with has_many_and_belongs_to associations to Articles. Each article has multiple Genres, and 1 format, but each Genre has multiple articles.
I know this should be simple, but I can't find the most efficient route of making this happen.
There's an old Railscasts episode that goes through the two ways to do many-to-many associations with Rails - you should watch it: http://railscasts.com/episodes/47-two-many-to-many. It's old but mostly still relevant.
So, you've got Articles, Formats, and Genres. Since each Article will have only one Format, you don't need a has_and_belongs_to_many relationship there. Article belongs_to Format, and Format has_many articles.
Each row in the articles table will have a format_id field to indicate which Format it belongs to.
The relationship between Genres and Articles is a many-to-many, which is a bit trickier. At the database level, this requires a 'join table'. Your join table would be called something like articles_genres, and each row represents one genre that one particular article has. So, it'd have a genre_id column, and an article_id column.
In terms of rails, there are two ways to do this:
Give the articles_genres table it's own model. In this case you might want to also give the table a different name, to indicate it's a Model in it's own right, not just a join table. You could call it something like genreizations
or
Don't give articles_genres table it's own model, and let rails handle it all.
I generally prefer the first way - I feel more in control, and it leaves things more flexible for future. But, either will work. The railscasts episode I linked to describes both ways.
If you go the first way, this is what models you'll have:
class Article < ActiveRecord::Base
has_many :genreizations
has_many :genres, through: :genreizations
belongs_to :format
end
class Format < ActiveRecord::Base
has_many :articles
end
class Genreization < ActiveRecord::Base
belongs_to :article
belongs_to :genre
end
class Genre < ActiveRecord::Base
has_many :genreizations
has_many :articles, through: :genreizations
end
And in the second way, this is what models you'll have:
class Article < ActiveRecord::Base
has_and_belongs_to_many :genres
belongs_to :format
end
class Format < ActiveRecord::Base
has_many :articles
end
class Genre < ActiveRecord::Base
has_and_belongs_to_many :articles
end

Ruby on Rails: choosing between has_many :through and simply has_many

I'm trying to create a linkedin clone, in which users can have several skills. They can also have descriptions for each skill and choose whether the skill is their primary skill or secondary skill (they can have only one of each).
I can't decide whether to just use a has_many or has_many :through.
If I use has_many
class Skill < ActiveRecord::Base
belongs_to :user
validates :description, presence: true
validates :name, presence: true
end
class User < ActiveRecord::Base
has_many :skills, dependent: :destroy
end
Skills table will also have columns primary and secondary, which are booleans.
If I use has_many :through
class Skill < ActiveRecord::Base
has_many :users, through: :users_skills
has_many :users_skills
end
class UsersSkill < ActiveRecord::Base
belongs_to :user
belongs_to :skill
end
class User < ActiveRecord:Base
has_many :skills, through: :users_skills
has_many :users_skills
end
Here, I will have the primary and secondary boolean columns in the UsersSkill model.
Which do you think would be a better choice?
Based on both your stated requirements:
I mainly want people to be able to type in a skill to search for
people with that skill
 
They can also have descriptions for each skill and choose whether the
skill is their primary skill or secondary skill (they can have only
one of each).
And on just my understanding of the meaning of the models, i.e. that a "Skill" is something which doesn't necessarily belong to a single user -- I'd go with has_many :through.
Reason for this is that the skills are things that stand on their own (and as you said, you want to be able to search for them). Just because one person lists, say, "Scrubbing Floors" as their primary skill, and another as their secondary skill, doesn't mean you should have two entries with "Scrubbing Floors". Have a single Skill for it, and use UsersSkills to assign it to multiple users, along with any information specific to that user's instance of the skill.
You can put the primary/secondary ranking on the users_skills table. The existence of this model will also save you a lot of effort in the future should you ever need to expand the information stored in these mappings.
The bottom line is that the choice depends on one piece of functionality of your system - whether a users' skills are specific to them, or part of a wider group
The has_many relationship will be good if your user will add their skills themselves
The has_many :through relationship will be good if your user's skills can be selected from a wider pool
--
System
You have to remember that since Rails is object-orientated, the setup of your ActiveRecord associations is primarily based on the association of the objects in your system.
many-to-many associations are primarily based on the sharing of objects between two models; whilst one-to-many associations are the result of a model having lots of dependent data
To make the decision, I would simply look at what you've got. If you want to pre-populate the skills, as per the likes of LinkedIn, go for the has_many :through

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/

Ruby on Rails belongs_to vs. has_one associations - clarification requested

In the following instance, what would the difference be between using belongs_to :mother and has_one :mother for the Chlid class? I've been reading the Rails documentation on this and I can't see how either one would make a difference apart from the semantics involved with reading it.
From what I can tell, the various associations add extra methods to each class, but I haven't been able to find the documentation to list per association what the methods are and what they do.
class BiologicalMother < ActiveRecord::Base
has_many :children
end
class Child < ActiveRecord::Base
belongs_to :biological_mother
end
In your case the has_many belongs_to is the right approach not just semantically but as how rails works. The foreign key is always stored in the belongs_to part of the association.
A valid has_one scenario could be like having a Purchase model which has_one BillingAddress.
example:
class Purchase
has_one :billing_address
end
class BillingAddress
belongs_to :purchase #this holds the foreign key - purchase_id
end
Regarding your case, you cant use has_many in one side and has_one at the other side of the association because the belongs_to part holds the foreign key always.
Let me know if this works for you.
At this point, it's almost purely semantics. With mongoid, I know that the foreign key is stored on the model with the belongs_to, so there might be something like that with ActiveRecord too.

Resources