Rails associations has_many through instead of HABTM - ruby-on-rails

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.

Related

Voting for nested objects using Acts as Votable gem in a has_many through association

Using this answer Voting for nested objects using the Acts As Votable gem I was able to get voting working for my app but not exactly what I was hoping for. In Carl's example his "dish" model belongs_to :dish_category but my setup looks more like this:
class Dish < ActiveRecord::Base
has_many :restaurants, through: :dish_categories
end
Right now when someone votes for a dish, it counts as a vote for that dish regardless of the restaurant. I would like to figure out if it's possible for dishes to have separate voting counts based on current restaurant. So if I'm a user I can vote up pizza at one restaurant but then vote down pizza at a different restaurant.
So, after getting a bit more data together, I think I have a solution that, although seemingly complicated, it's simple really and organized.
I would suggest that you have your Restaurant and Dish models, as well as your DishRestaurant join table (or DishCategories as you have it in your original post), and finally a VoteContainer to hold the logic for votes.
class Restaurant < ApplicationRecord
has_many :dish_restaurants
has_many :dishes, through: :dish_restaurants
end
class Dish < ApplicationRecord
has_many :dish_restaurants
has_many :restaurants, through: :dish_restaurants
def votes
dish_restaurants.vote_container
end
end
class DishRestaurant < ApplicationRecord
belongs_to :dish
belongs_to :restaurant
has_one :vote_container
end
class VoteContainer < ApplicationRecord
act_as_votable
belongs_to :dish_restaurant
end
I was thinking of something along these lines may work. In theory, dish.votes should be your gateway to the logic for managing votes
Original Reply (disregard)
So, what I'm thinking is you may have what may feel like duplicate dishes. So, you'll create a new pizza dish for each restaurant that offers pizza. Technically it's not a duplicate, as it has it's own vote count for that particular restaurant. This would probably be the easiest and most sensible way from what you're currently presenting.
This makes sense also because not every restaurant makes pizza the same way as others. Each pizza may have different attributes (price, ingredients, etc). If you do it the way I've suggested, you'll be open to these p

Rails STI design issue

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

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

Rails Associations Planning

I'm still making my way with Rails and I have a question about associations.
I'm building a fitness website and I want to have users track their workouts. I'm a bit unsure as to how the associations should go. What follows is what I currently have.
A Workout is made up of a group of exercises. The user would create a workout object to save all the exercises together so as to not have to repeat the creation process every time. On top of that I don't want them to have to re-create exercises to add it to a new workout. So, both workouts and exercises would belong to a user.
My planned associations are this.
Workout
belongs_to :user
has_many :exercises, :through => :routines
Exercise
belongs_to :user
has_many :workouts, :through => :routines
Routines
belongs_to :workout
belongs_to :exercise
User
has_many :workouts
has_many :exercises
//the rest of the user associations
I think this is correct, but having both workout and exercise belonging to the user seems somewhat redundant to me. Is this the best setup or is there another way to associate these things? Any help is appreciated.
I see there is no need of having Routines there.And you need to tweak your Associations.
How about like this
Workout
belongs_to :user
belongs_to :exercise
User
has_many :exercises
has_many :workouts :through => exercises
Exercise
has_many :workouts
belongs_to :user
Personally, this seems a bit more logical to me:
class User
has_many :workouts
class Workout
belongs_to :user
has_and_belongs_to_many :exercises
class Exercise
has_and_belongs_to_many :workouts
In my opinion exercises only belong to one or more workouts and it has little to do with an user. Therefore I would omit the association between users and exercises.
Since workouts can share similar exercises there is a many-to-many relationship between them. Usually I go for a has_many, through relationship in these cases, but since you do not mention possible additional attributes for the join model has_and_belongs_to_many with a join table should suffice.
EDIT: The associations are probably a bit more complex the more you think about it. For example, a workout can actually belong to multiple users. I think it would be best to go to the drawing board and draw the associations and the attributes per model.

creating a schema with products with infinite categories and infinite sub-categories

I've been doing a lot of research on what is the best approach to developing a schema for a new feature on a project I am working on.
I will have products that can be associated with an infinite number of categories and in infinite number of sub-categories.
As I started get frustrated I started to think that maybe I am just over thinking it. I'm wondering if the active record associations below make sense to you and you can foresee any possible gotchas.
class Product < ActiveRecord::Base
has_many :categories
has_many :sub_categories, through: :categories
end
class Category < ActiveRecord::Base
belongs_to :product
has_many :products
end
class SubCategory < ActiveRecord::Base
belongs_to :category
end
At this point, just go with what you have.
IF you start seeing a lot of overlap in both data and behavior (instance methods) or if you find yourself always wanting to access categories and sub categories together you could start looking at:
Self joins - which would let you keep both categories in the same table and as the same type of model
Ancestory - additional flexibility for a full-on tree structure of data

Resources