Rails Associations Planning - ruby-on-rails

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.

Related

ActiveRecord many_to_many association confusion

I am creating a quiz in Rails and I am drawing a blank on my associations.
I say I have three tables that I know are going to be there.
users
|___id
|___name
quizzes
|___id
|___user_id
questions
|___id
|___question
|___poss_answer_one
|___poss_answer_two
|___poss_answer_three
|___answer
|___test_version
This is what I started with. The functionality of the site is as follows:
A user can select questions from up to three categories to add to their active quiz (quizzes). So a user will only have one quiz at a time because when they finish or restart a new one, the entry into the quizzes table will be re-created.
So the user has_one quiz and quizzes belongs_to users.
Next I am assuming that a quiz has_many questions and because questions are re-usable and can be included in many different quizzes, would it require a join table?
If so would it be
quiz_questions
|___id
|___question_id
|___quiz_id
In that case it would require a has_many through.
Once I get this done I know how to model the associations, I am just confusing myself because of the wording.
Probably you need a HABTM association (see this RailsCasts)
class Quiz < ActiveRecord::Base
has_and_belongs_to_many :questions
end
A user can have zero, one or many quizzes(not just one), so the association should be an has_many association not just has_one association, for clarify
a user has one quiz: user.quiz
a user has many quizzes: user.quizees
a quiz belongs to a user: quiz.user
Although a user can only have one quiz at a time, but after the user finished it, the user can have another new quiz.
user1 -> quiz1
user1 -> quiz2
user1 -> quiz3
for a many-to-many association, you can use has_and_belongs_to_many(if you don't need extra columns in the table, except quiz_id and question_id) or introduce a join table
There are a number of valid approaches (I would argue). Following through with your has_many through suggestion the following could work. (Although a HATBM will certainly be simpler to implement and also valid for most use cases).
class Question < ActiveRecord::Base
belongs_to :category
has_many :quiz_questions
has_many :quizzes, through: :quiz_questions
class QuizQuestion < ActiveRecord::Base
belongs_to :quiz
belongs_to :question
class Quiz < ActiveRecord::Base
belongs_to :user
has_many :quiz_questions, dependent: :destroy
has_many :questions, through: :quiz_questions
You wrote:
a user will only have one quiz at a time because when they finish or
restart a new one, the entry into the quizzes table will be
re-created.
I would say that even if this is the case you still require a has_many relationship. You are not 'recreating' the record in the quizzes table. You will be creating a new record. As a separate piece of functionality you may decide to delete to the(any) existing record in the quizzes table that belongs_to that particular user if these 'old' records are no longer required at all.

Which assosciation to use in Rails?

I have a user and project model created in Rails. I have to perform an association that will create an relationship which is described below:
1 User has many Projects
1 project has many Users
How can I go about creating an association for the same in Rails? I need some help on which type of association in rails will help me to achieve this.
You are describing a many-to-many relationship type. Rails allows you to create this relationship using has_many :through and has_and_belongs_to_many directives. You can learn the difference here.
Shortly, has_many :through allows you to add additional columns into the intermediate table, has_and_belongs_to_many doesn't. If you don't need to have additional attributes in the intermediate table than use has_and_belongs_to_many syntax. You can always change to has_many :through later.
class Project < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :projects
end
You are basically trying to have a many-to-many relationship.
In Rails you can do this based on two association concept:
has_and_belongs_to_many (HABTM)
has_many :through
Note:
You should have HABTM if you just do not care about the way these two tables are joined (relationship model) and you do not want to have any logic/validation for your join data. It will just keep your foreign keys in a table and based on that data will be fetched.
You need has_many :through if you want to have an intermediate model in between Project and User which can be called as UserProject model. This way your association could look like as follows:
User Model:
has_many :user_projects
has_many :projects, through: :user_projects
Project Model:
has_many :user_projects
has_many :users, through: :user_projects
UserProject Model:
belongs_to :user
belongs_to :project
You can use has_and_belongs_to_many or has_many through.Here is the link I am providing which will help you to sort out difference between them and which one will be good for you.Here is the video tutorial for you association.ALso there is a good link link.In your case you need has and belongs to many
The best thing to do in this situation is ,
In your user.rb model file:
has_and_belongs_to_many :projects
and In your project.rb model file:
has_and_belongs_to_many :users
You may want too use many to many relationship between project and user. on top of that you may want to visit rails official guide which describes all of these relations in great detail.
http://guides.rubyonrails.org/association_basics.html

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.

Using multiple has_many associations on one model

I am working in a rails app where a Company has_many orders. An order has a name and that is it. The order can have_many television_spots, radio_placements, and newspaper_placements, the data in these tables is not the same so they have to be split up. Now if an order has_many radio_placements it will not have television_spots or newspaper_placements. My question is it bad practice to have a has_many relationship on a model even if it does not exist?, would it be better better to make a Company have_many television_orders and a television_order have_many television_spots? And thus a Company have_many radio_orders and a radio_order have_many radio_placements, and so on. I think that the first option is dryer initially but using the second strategy could result in cleaner more understandable code as the app grows and what we do with the data changes.
It's not bad practice to have a has_many association that does not actually have any models associated. The real question is what object type the radio_placements, television_spots and newspaper_placements should really be associated to. If they should in fact be related to the Order model, then place the associations there. From my understanding of your question/data shape it would appear that you do want these relationships to be on the Order model. So something like:
class Company
has_many :orders
has_many :television_spots, through: :orders
has_many :radio_placements, through: :orders
has_many :newspaper_placements, through: :orders
end
class Order
has_many :television_spots
has_many :radio_placements
has_many :newspaper_placements
end
Hopefully that helps.

Ruby on Rails ActiveRecord task belongs to company & has_many users

I'm new to Ruby on Rails and was wonder if this is a good setup, or if there is a better configuration.
Background:
The system will be used to assign tasks to users, track the assignor, and allow multiple people to be assigned the task.
Create a company model, user model, task model, and a user_tasks model.
Company Class
has_many :users
has_many :tasks
User Class
belongs_to :company
has_many :user_tasks
has_many :tasks, through: :user_tasks
Task Class
belongs_to :company
has_many :user_tasks
has_many :users, through: :user_tasks
UserTasks Class
belongs_to :user
belongs_to :task
*Tracks assignor with boolean
I think this is perfect. There is one big advantage of having a has_many (model1), through: (model2) association when compared to has_and_belongs_to_many association in that you can access the join model (UserTasks your case) through the ActiveRecord query interface (UserTask.where() or UserTask.find_by(user_id: 1) and so forth). Querying the join table directly can sometimes shorten your queries. If you use the has_and_belongs_to_many association you will have a database table that you cannot directly access in Rails without resorting to SQL.
You probably don't need the UserTasks class if it is just a habtm table. So just create a migration for that table, but skip adding the model. Then in User, do has_and_belongs_to_many :tasks and in Task do has_and_belongs_to_many :users
The other thing that I see is that company is set for both tasks and users. You might have business rules to why this has to be, but if not, you might just be able to say Company -> has_many :tasks, through: :users
I favor :has_many, :through over has_many_and_belongs_to_many or HABTM. For example, I can be assigned to a Task twice, one as a programmer and another time as a designer. So I need some kind of "JobDescription" column on the UserTask column, and I'd need two rows of the UserTask table to represent me being a programmer on a task, and another to represent me being a designer on a task.
You want to write software that is easier to change, even though HABTM is shorter, you might change the software in the future, like in the case of a person doing two subtasks in the same task. Remember that a row in a database is a piece of data, or "a thing", if that makes sense. At the very least, you get timestamps.

Resources