Creating and querying questions/answers in Ruby-on-rails - ruby-on-rails

We're creating a Ruby-on-rails application where the user is presented with a series of questions where they can give multiple different answers to one question. For now it's it's toggles but in the future we might be interested in doing freeform text as well. Each group of answers is connected to a pin on a map.
For now, each pin simply has a coplumn of questions and answers, which is a hash, but we'd really like to make it nicer and more scaleable. Some of the queries we'd like to do are e.g. count the amount of people that have answered 'It's quiet here' to the question 'Why do you come here?'
For now, I thought of the following models:
# pin.rb
class Pin < ApplicationRecord
has_many :questions
end
# question.rb
class Question < ApplicationRecord
belongs_to :pin
has_many :answers
end
# answer.rb
class Answer < ApplicationRecord
belongs_to :questions
end
Is this the right way of approaching this? I'd then fill seed.rbwith the questions and possible corresponding answers.
What's the best way of then creating new objects or rows, when a user answers a given question?

This looks good to me. If your Answer defines possible choices for a question, then for storing user answers/selections, you'll have to create another model/table
class UserAnswer < ApplicationRecord
belongs_to :question
belongs_to :answer
# attribute :value
end

Related

How to create model with multiple fields for answers?

I created a model Question with question:string and answer:string.
I want to create questions with multiple answers(1-30), but in the db there are only two tables(one for question, one for answer).
For example, I have a field for questions and a lot of fields for answers which I can add dynamically. After that I want to display question and all answers that belongs to it. How do I do this?
You are going to want to separate those concerns.
What I mean is:
Make a separate Answer model and migration so you can create an 'answers' table in your database. That way you can put this in your Question model:
has_many :answers
and in your Answer model:
belongs_to :question
I'd say this is the proper way to achieve what you are looking for.
Define Question and Answer model as
class Question < ActiveRecord::Base
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
end
RUn migration
rails g migration addQuestionIdToAnswers question_id:integer
So now you can say question.answers and this will give you all the answers which belong to that question. as you have question_id field on every `answer'
You can make calls like
answer.question # return the question the answer `belongs_to`
question.answers # return all the answers the question `has_many`

Scaling large data in Rails4

I'm making a Q&A site. I have three models for now:
Question
Answer
User
Both Question and Answer can be voted for, so I need a way to store who voted on the model, to prevent multiple votes on one model by same user.
Would be a good idea to create a vote model? Where either the question_id or the answer_id will be empty in each. I'm afraid that this will create a lot of junk and slow the application down.
My other idea is to store the user_id in a hash in the Answer and in the Question.
If the user is already present in the hash it prevents voting. Or store the answer and question ids in the user.
What would be the Rails4 way to be fast but store most user interactions in models. What can be KISS, DRY and fast?
You should use a polymorphic model if you have multiple models the Vote can refer to.
class Vote < ActiveRecord::Base
belongs_to :voteable, polymorphic: true
end
class Question < ActiveRecord::Base
has_many :votes, as: :voteable
end
class Answer < ActiveRecord::Base
has_many :votes, as: :voteable
end
I don't think you have to worry about the speed for quite a while if you use indexes on the associations. Just put this snippet in a migration and you should be good to go!
add_index :votes, [:voteable_name, :voteable_id]

has_one based on attributes from a has_and_belongs_to_many relationship on the same model - ruby on rails

I have the following models:
class Audit < ActiveRecord::Base
has_one :country, :through => :another_model
has_and_belongs_to_many :questions
end
class Question < ActiveRecord::Base
has_and_belongs_to_many :audits
has_many :details # one detail for each country [england, wales, scotland etc]
has_one :detail, :conditions?
# i want it to have one detail dynamically depending on the audit
end
class Detail < ActiveRecord::Base
belongs_to :country
belongs_to :question
end
The problem is regarding the question model. Say for example I have Audit A with Questions 1, 2 and 3 and Audit A is based in the country England. When viewing Audit A I want to display the 3 Questions; no problem. #audit.questions.each do |q| etc
Now let's explain the question details. Let's say I have Detail X, Y and Z. Detail X, Y and Z are all associated with Question 1. However, Detail X is based in the country England, Detail Y in Wales and Detail Z in Scotland. At the moment I have all details pulled out of the database and then in the view/model I get the current audit's country and subsequently get the detail based off that.
Is there a way to say something along the lines of:
class Question < ActiveRecord::Base
has_and_belongs_to_many :audits
has_one :detail, :conditions -> {country_id = current_audit_being_viewed.country.id}
end
I'm also aware I could just be thinking about the relations in the wrong way so please feel free to just tell me a better way all together to do what I'm trying to achieve.
just to clarify things. In your post you said:
class Question < ActiveRecord::Base
has_and_belongs_to_many :audits
has_one :detail
end
and
class Detail < ActiveRecord::Base
belongs_to :country
belongs_to :question
end
You also mentioned
"Now let's explain the question details. Let's say I have Detail X, Y and Z. Detail X, Y and Z are all associated with Question 1". Which says that one Question can have many Details.
But based on the model declarations you made above, Question only 'has_one' Detail. Please verify. Thanks!
For the problem you have, you can try using model 'scope':
class Detail < ActiveRecord::Base
belongs_to :country
belongs_to :question
scope :with_country_id, -> (country_id) { where( country_id: country_id ) }
end
So assuming the Question has_many Detail(s), then you can:
question.details.with_country_id( current_audit_being_viewed.country_id )
Also, try using has_many :through. Could make things a lot easier to design (and prettier). ;)
Hope that helps! :)
Cheers!

How to create voting to a multiple choice application using ruby on rails

I am working on a multiple choice question and answer application using Ruby on Rails and I have the following model.
class User < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
has_many :votes
end
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :answer
end
My problem is a user can choose all the answers.
How can I fix it so that it updates to the new answer?
For example, a has 5 votes and b 3 votes.
User clicks on a and a increments to 6 votes, same user comes back and clicks on b, a decrements back to 5 votes and b increments to 4 votes.
My first guess is that I need to add another model for example, user_choice with user_id and vote_id to track the previous answer.
You have your answer within the models. Just add a point system to the question model.
Under the question model,
def points
self.answers.count
end
Or, if answers have different values attached to them, make points an attribute of the answer instances.
def points
self.answers.pluck(:points).inject(:+)
end
This will sum up all the points from an answer belonging to a question, which allows you to order the questions by point count.
However, I am assuming you will need a Choice model for a question, unless that is in fact what the votes are for.
question has_many choices
choices belong_to question, etc.
I'm not sure what you mean when you say:
How can I fix it so that it updates to the new answer?
EDIT
Er, okay so you just need exactly what I mentioned earlier. A vote is really just the number of times an answer has been chosen.
If your problem is that users can choose more than 1 answer, it is likely that you should implement view based validations via javascript, or better yet, just disable their ability to select multiple choices, which if you were using a select tag, is actually the default. You must've added
multiple: true
in the select tag options for the user to select multiple entries.
On the backend, you can do this:
class Choice < ActiveRecord::Base
validates_uniqueness_of :user_id, scope: [:question_id, :answer_id]
end

How to connect models in a form without nesting?

I did a lot of searches for this problem and watched quite a few tutorials (e.g railscast: nested model form) but I'm afraid it's not the right solution to my problem.
I want to collect data for a theory. This theory has many questions to be answered on distinctive cards. I always want to display all questions (on all cards), but the answers may vary, depending on each card. Therefor I need to catch the question_id and card_id, but deep nesting and catching the id by params would be quite a pain. Does anyone know a better solution for my problem?
Here are my models:
theory.rb
class Theory < ActiveRecord::Base
has_many :cards
has_many :questions
card.rb
class Card < ActiveRecord::Base
belongs_to :theory
has_many :answers
has_many :questions (Do I need this here - I always want to display all questions?)
question.rb
class Question < ActiveRecord::Base
belongs_to :theory
has_many :answers
answer.rb
class Answer < ActiveRecord::Base
belongs_to :card
belongs_to :question
Thank you a lot for your help!
The relationships between your models should not be determined by how they will be displayed on the screen. They should be determined by how they are actually related to each other.
I don't fully understand what theory/card are supposed to represent so I can't tell you what relationships need to exist, but I can have a stab at at it :
It seems to me as though a card represents the answers for a single person that relate a to a specific Theory? If so, then you don't need the "has_many :questions" because the card only has answers. Also, each answer links to a question so you can "get" to the questions through the answers. You could add a "has_many :questions, :through=>:answers" to the Card model if you really wanted the list of questions for a card.
If each card can have a different set of questions added to it before any answering is done, then you will need the "has_many :questions", but if all the questions are on each card then you won't need it.
Update in response to your comments below :
One way is to add the answers to the card by building them up in the controller:
#card = Card.find 2
#theory = Theory.find 1
#theory.questions.each do |question|
#card.answers.build :question=>question
end
Then in your view do something like this (this is HAML) :
= form_for #card do |f|
-#card.answers.each do |answer|
=f.fields_for answer do |answer_form|
=answer_form.hidden_field :question_id
%p=answer.question.full_question
%p=answer_form.text_field :input
This is using nested form attributes, so to get it to work with your Card model you'll have to add this to it :
class Card < ActiveRecord::Base
..
accepts_nested_attributes_for :answers
..
end

Resources