HABTM, or multiple belongs_to? - ruby-on-rails

I'm teaching myself Rails, and as a test project I'm mocking up a simple question/answer app similar to stackoverflow.
In my simplified version I have:
questions
answers
users (the authors of questions and answers)
I get that answers belong to questions.
What's the proper relationship between users and questions?
What's the proper relationship between users and answers?
It would seem to me that questions and answers don't really "belong_to" users, and instead questions and answers "has_one user" (the author). But that doesn't seem right either, because then the user would "belong_to question" and "belong_to answer".
Is HABTM the answer between the three classes?
Lots of people get stuck on this relationship thing, don't they? :)

Is HABTM the answer between the three classes?
No. You don't need HABTM in any of these relationships.
What's the proper relationship between users and questions?
What's the proper relationship between users and answers?
In both of these cases, it is a one-to-many relationship: A user has many questions and a user has many answers.
From a logical point of view, consider this: One question can never be authored by multiple users and one answer cannot be authored by multiple users. As such, it's not a many-to-many relationship.
In this case, your classes should be set up like this:
class User < ActiveRecord::Base
has_many :questions
has_many :answers
end
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
If you, on the other hand, have a tagging system similar to StackOverflow, you'll need a HABTM relationship. One question can have many tags, while one tag can have many questions. As a prime example, your post has three tags (ruby-on-rails, habtm, foreign-key-relationship), while the ruby-on-rails tag presently have 8,546 questions.

Belongs_to is a strange name. Figure out your has_many relationships and just put belongs_to on the other side and don't worry about the semantics of it.

Related

Anything wrong with this plan for my model associations

I'm creating an app that allows users to take multiple choice quizzes that I create.
There's a Quiz model, a Question Model, and an Answer model. The Quiz model has_many questions which has_many answers (and they all belongs_to the model intuitively above them). answers will have a correct_answer boolean attribute that indicates ONE of the answers to be the correct answer. (and they all belongs_to the model intuitively above them). This is to create the quiz.
To provide support for user input once the quiz has already been created, I want to define two other models: SubmittedAnswer and SubmittedQuiz. SubmittedSurvey belongs_to User, and also belongs_to Quiz (both of which has_many submittedsurveys). SubmittedQuiz also has_many submittedanswers.
So when you visit the page that displays the quiz, it allows user input which submits data that sets submittedanswers. Then, since submittedQUiz belongs_to Quiz, I can compare submittedanswers to the answers themselves and grade the quiz. Is this reasonable or should I do it some other way?
I think SubmittedAnswer should have a link (belong_to :answer) so that you can know which answer (and by relation which question) the user responded to.

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]

Difficulty with belongs_to and has_many

I'm rather confused by the construction and have tried several ways to get the following situation to work for my test. But I can't get it to work.
This is what I want:
When an activity is being made. Several clients can be assigned to that activity. Therefore creating access to #oneActivity.clients or #oneClient.activities.
Should I put up a references :client in my activity migration or the other way around? And which of the two should have to belongs_to in the model and which the has_many?
well if a client has many activities and an activity has many clients then i suggest you take a look at has_and_belongs_to_many relationship.in that case
in your Client model you would have
has_and_belongs_to_many :activities
and in your Activity Model you would have
has_and_belongs_to_many :clients
that way you can do the actions you described in your question
You can check out relationships from the rails guides here: http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
I guess, from what you describe, that you need a many-to-many relationship. Clients can have many activities, and activities can, as you describe, be assigned to several clients.
Setting up such a relationship is described in the following question When should one use a "has_many :through" relation in Rails?
in your Client model you would have
has_and_belongs_to_many :activities
and in your Activity Model you would have
has_and_belongs_to_may :clients

Ruby On Rails Relationships - One to Many

I'm a beginning to ROR, but here's what I'm trying to achieve. I have two items I want to associate: matters and people. Each matter can have many people. That is, I want to create people and matters separately and later be able to link them.
For example, I may create:
Bill Clinton
Barack Obama
I may create the matters:
Global warming
War on terror
I want to be able to associate the users Bill Clinton AND Barack Obama to BOTH matters. Can someone point me to a tutorial that can show me how to do this?
I think has_and_belongs_to_many is used less and less by the RoR community now. While still supported, I think it is now more common to have an intermediate model (in your case something like PoliticianMatter) to join your Politician and Matter models.
Then your politician_matter table will have a PK, a politician_id and a matter_id.
Then you have
class PoliticanMatter < ActiveRecord::Base
belongs_to :politician
belongs_to :matter
end
The advantage of this approach is that if there ever need to be future properties of the politician -> matter relationship (e.g importance, date of last occurrence) you have a model which affords this - has_and_belongs_to_many would not support the addition of these extra properties.
You can also access the many to many relationship directly from the Politician and Matter models like this
class Politician < ActiveRecord::Base
has_many :politician_matters
has_many :matters, :through => :politician_matters
end
class Matter < ActiveRecord::Base
has_many :politician_matters
has_many :politicians, :through => :politician_matters
end
You need a many2many relationship between these two entities.
A matter can be studied by many people
A person can studie several matters
Rails uses the has_and_belongs_to_many helper to do that. You'll find more about that in the documentation and many many blog posts!
has_and_belongs_to_many helper
class Politician < ActiveRecord::Base
has_and_belongs_to_many :tasks
end
class Task < ActiveRecord::Base
has_and_belongs_to_many :politicians
end
What you need are 3 tables:
politicians, tasks and politicians_tasks (having the two columns politician_id and task_id, no primary key)
Hope this helps
Seb

Resources