I am using a :through relationship between 2 models because I have extra data I want to store in the join table -- otherwise I would just use the :source relationship.
But the data I want to store is dynamic -- it's a list of questions that have been added to an instance of one of the models I am joining. Example:
Physicians add unique questions that patients should answer when making an appointment -- Dr. Foo wants his patients to answer 'height' and 'weight', while Dr. Bar wants his patents to answer 'age' and 'gender'.
What is the cleanest way to store the answers to these questions in the Appointment model instance?
current Models:
class Question < ActiveRecord::Base
belongs_to :physician
end
class Physician < ActiveRecord::Base
has_many :questions
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, through: :appointments
end
Thanks in advance -- I have come across this several times and would love to hear a good answer on it -- another example is: User takes a Quiz. Quiz has_many Questions.
How would you store the unique answers to the static set of questions each Quiz has? Again, I'm stuck at using a :through relationship using a join table called Attempts.
Possible solution I thought of: Patient has_many Surveys and Survey has_many Answers. Create this when a new Appointment is made. Problem is, I'm finding the views and controllers to be quite complex for something as simple as, to restate my question, store data related to a joining table.
I'd recomend adding a new model called Answer for storing this information. Something like
class Answer < ActiveRecord::Base
belongs_to: appointment
belongs_to: patient
end
The relationship with the Question model could be difficult to maintain. Think of a question that has already been ananswered and changes its text from 'how old are you?' to 'when did you born?'. You'll have to prevent this change at the question model or store the question text with the answer and forgot the relationship.
Another option would be to use a serialized atribute on the appointment model to store its questions and answers.
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
serialize :answers
end
You'll need to add a text attribute to the appointment table called answers
The answers attribute will be a hash where you can save something like {question_text_1: answer_1, question_text_2: answer_2}. This will allow you to easily use it on the view.
It's also easy to write the method to save/update this attribute allowing an easy form on the corresponding view.
Again, it's necesary to define what will happen to old appointments when a physician changes question titles.
I think you need two extra tables here: Answer, and AppointmentQuestion. There is the tricky issue of the questions_to_ask, the questions_answered and answers. I've addressed the questions_to_ask by delegating from the appointment to the physician, giving Appointment.physician_questions. The idea is the appointment will know what questions to ask, and will store the questions answered
I got to this solution by drawing entiry relationship diagrams and then looking at creating intermediate object where m-m relationships exist. The stuff below isn't complete.
This suggests a general solution of having a table that contains a row for each time the question is asked (perhaps rename AppointmentQuestion to AskedQuestion)
AppointmentQuestion
belongs_to :question
belongs_to :appointemnt
has_one :answer
Answer
belongs_to :AppointmentQuestion
Appointment
belongs_to :physician
belongs_to :patient
has_many questions through appointment_question
has_many answers through appointment_question
delegate :questions, to: :doctor, prefix: true
Patient
has_many appointments
Physician
has_many appointments
has_many questions
Question
belongs_to physician
has_may answers through appointment_question
I don't know which database you are using but to me that looks like the perfect example for using Postgres HStore. Considering your data is dynamic, unstructured.
http://www.postgresql.org/docs/9.1/static/hstore.html
You could have a field questions of the type hstore
On your appointment migration
def change
create_table :named_searches do |t|
t.hstore questions
end
end
And you would have that field available on your models (it works like a hash with key value pairs, questions and answers in your case)
When you query for questions on that case, you will get a list of questions with their respective answers, and although the list is dynamic (any question can be added/the appointments don't need to have the same questions), it can be saved to the database seamlessly
Related
I want to manage the association of one to many type, for user and answers and association of many to many type, for vote management for the same two models i.e users and answers.
So, how to maintain both the associations at the same time?
This code is something that I want to implement.
class User < ActiveRecord::Base
has_many :answers #For the answers of particular user
has_and_belongs_to_many :answers #For the answers upvoted by a particular user
end
class Answer < ActiveRecord::Base
belongs_to :user #Author of the answer
has_and_belongs_to_many :users #For those who upvoted the answer
end
You should give a different name to the other association, but then you would also need to specify class name.
has_many :answers
has_and_belongs_to_many :voted_answers, class_name: "Answer"
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.
I have the following model structure:
class Test < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :test
belongs_to :answer, class_name: 'Choice'
has_many :choices, dependent: :destroy
end
class Choice < ActiveRecord::Base
belongs_to :question
has_one :question_answered, dependent: :nullify, class_name: 'Question', foreign_key: 'answer_id'
end
Now I wanted to create a single form where the user could create/save the tests params and edit all the questions and their choices, and also select which one is the correct answer.
The problem arrives when the user is creating a new question. None of the choices have an id and, therefore, I don't know how to define which will be the correct answer without having to write extra code on my controller (only using accepts_nested_attributes_for).
What I did is: Before saving the nested attributes of Test (but saving test before), I fetch from params all the questions and choices that don't have an id and save them. After that I update the answer_id params for all the questions.
This solutions is working right now but I don't think it's the most elegant one. Knowing Rails and its awesomeness, I know there is a better way of doing this. What do you guys suggest?
I am building a multiple choice survey with a set of fixed questions and fixed answers. A question has_many answers and an answer belongs_to question. The questions and answers will be seed data in the db and will be written in the seeds.rb file.
I am trying to figure out how to relate the surveys to the questions and answers. Users can pick from taking a short or long survey, each of which will have a different amount of questions. So a survey needs to be able to keep track of which questions it has, and the answers chosen for each question. I've started out with this relationship for surveys and questions:
class Survey < ActiveRecord::Base
has_and_belongs_to_many :questions
end
class Question < ActiveRecord::Base
has_and_belongs_to_many :surveys
end
Now I can't figure out how to put answers into this. A question has_many :answers, but how do i relate the answers to surveys? I was thinking a has_many through relationship, but I can't see how that would work.
Any ideas?
class Survey < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
has_many :answers
belongs_to: survey
end
class Answer < ActiveRecord::Base
belongs_to :question
end
Suppose, for any specific survey,
Survey.find(1).questions.collect{|x| x.answers}
In this way you can find an array of arrays which contains each question with answers. I guess this is what you need.
I'm getting crazy adding some features to my quiz app based on Rails and Active Record.
This is my actual data model:
class Quiz < ActiveRecord::Base
has_many :quiz_questions
has_many :questions, through: :quiz_questions
belongs_to :user
end
class Question < ActiveRecord::Base
belongs_to :section
has_many :answers
has_many :quiz_questions
has_many :quizzes, through: :quiz_questions
end
class Answer < ActiveRecord::Base
belongs_to :question
end
class Section < ActiveRecord::Base
has_many :questions
end
class User < ActiveRecord::Base
has_many :quizzes
end
Question and answer are obvious: I store the questions and every question has some answer.
The logic now is working right.
User create a quiz, the system take some random questions and add them to the join table.
I must add now some stats: I want to add the possibility for every user to track the right answer percentage and the questions with more errors and I want also to give to every user the possibility to choose a "quiz generation strategy", overriding the "randomness" of the question choice. User for example can create a quiz with questions he never answered (there are about 1200 question in the table and every quiz has 30 questions), or user can create a quiz with questions he wrongs often.
I cannot find a way to add these counters in a smart way. I have my join table, but using the join table I have poor performance. Any idea?