ActiveRecord many_to_many association confusion - ruby-on-rails

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.

Related

Rails 5 - belongs_to but has_many association

I am currently trying to create a system which allows for specific users to create a Course record which can be enrolled in by many other users. I've tried a few association techniques such as has_and_belong_to_many, has_many :through and number of other setups but have been unable to get it right.
Basically all that I need is the following:
Course belongs to (is created by) a single User (foreign_id => admin_id)
Course has many enrolled Users (Join Table?)
User has many created Courses
User can belong to many Courses
If you have any idea how this would be accomplished I would greatly appreciate your input.
I would use a Course model to represent the course information, with a user_id attribute to associate with the user who created the course. I would also make an association table/model called Enrollment which is an association between a User and a Course. You can then do something like this:
#User.rb
has_many :courses
has_many :enrollments
has_many :enrolled_courses, through: :enrollments, source: :course
#Enrollment.rb
belongs_to :course
belongs_to :user
#Course.rb
belongs_to :user
has_many :enrollments
has_many :users, through: :enrollment
With this configuration you can call course.user to receive the user who created the course, but you could also call course.users to receive the users who are enrolled in the course. On the opposite side, you can call user.enrolled_courses to receive the list of courses a user is enrolled in, or user.courses to receive a list of courses a user has created.

Model Structure & has_many Association Migrations

I'm trying to set up models in such a way that Users can create Lessons and then other users can sign up for them.
Right now my models are set up like this:
class Lesson < ApplicationRecord
belongs_to :teacher, class_name: 'User'
has_many :students, class_name: 'User'
end
class User < ApplicationRecord
has_many :lessons
has_many :students, :through => :lessons
end
I want to be able to access the users signed up for a lesson by #lesson.students for example. I'd also like to be able to get all the lessons that a student is participating in (can't really see how I'd do this with my current set up).
Are my model associations right for how I'd like to use them? If so, how can I create the migrations to add the necessary references to my database models?
If you want the ability to create nested resources from it's parents then you have to add:
accepts_nested_attributes_for
to the parent model.
Also, I recommend you to read how to set up has_many through relationships, you need a join model for rails to do its magic and link the 2 models
Once you set everything up, create the join model (with it's respective foreign keys, one for lesson and the other for user) rails will take care of the associations between the models, allowing you to do things like:
User.last.lessons #lessons created by the last user
and
Lesson.first.users #users subscribed to a lesson, in this case the first one

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 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.

rails, model naming question

I'm creating a model called Chats. And I want to assign users to a discussion. They are either a part of the Chats or they aren't...
So I create one model Chats.
What's the standard Rails naming convention for the other table?
ChatUsers?
While has_and_belongs_to_many is an ok option here, I recommend going with has_many :through instead.
In essence you will have an explicit join model, which you can call something like ChatSession.
class Chat < ActiveRecord::Base
has_many :chat_sessions
has_many :users, :through => :chat_sessions
end
class User < ActiveRecord::Base
has_many :chat_sessions
has_many :chats, :through => :chat_sessions
end
class ChatSession < ActiveRecord::Base
belongs_to :user
belongs_to :chat
end
Now you will need a table called chat_sessions with columns :user_id, and :chat_id in it. This is your join table.
Advantage
You get a model which is fully under your control, and isn't just a dumb join table managed by rails. So for example, if you want to track number of messages particular user left in particular chat, it could be a column in chat_sessions table. Presence of :through renders habtm unneeded in most cases. There is no complexity overhead either.
If it is a join table, it would be both table names joined by '_' and in alphabetical order of table names:
chats_users
This is called a has_and_belongs_to_many association in rails. You basically have two models that call has_and_belongs_to_many and create a linking table that uses the two models in the name (alphabetical and plural).
models:
class Chat < ActiveRecord::Base
has_and_belongs_to_many :users
end
class user < ActiveRecord::Base
has_and_belongs_to_many :chats
end
Then your tables would be
chats
users
chats_users

Resources