Rails has_one through relationship - sql

I have three tables: question, question_choices and response.
Question
ID
Name
Tag
Question_Choice
ID
Question_id
Label
Value
Response
ID
User_id
Question_id
Value
Given a response, I want to see the question tag and the question_choice label for that. Getting either response or choice to relate to question are no problem, but getting response to relate to choice is proving challenging because I need to say "value=value". I have tried setting up a :has_one, :through => :question relationship but i'm not sure how to express the "value=value" stuff. Do I just need to use raw sql?

I assume that you don't want to change the table structure (which would be the easiest solution). This is the solution for your current table structure:
app/models/question.rb
class Question < ActiveRecord::Base
has_many :question_choices
end
app/models/question_choice.rb
class QuestionChoice < ActiveRecord::Base
belongs_to :question
end
app/models/response.rb
class Response < ActiveRecord::Base
belongs_to :question
belongs_to :question_choice, :primary_key => 'value', :foreign_key => 'value', :conditions => proc { "question_id = #{self.question_id}" }
end
Response.first.question_choice will give you the question_choice of the first response.

I'm guessing questions have many question choices, and that responses have a single 'selected' question choice. To model this you would need a direct association between the response and question choice as well, e.g.
class Question < ActiveRecord::Base
has_many :question_choices
end
class QuestionChoice < ActiveRecord::Base
belongs_to :question
end
class Response < ActiveRecord::Base
belongs_to :user
belongs_to :question
belongs_to :question_choice
end
This means that you would need to add a question_choice_id column to your responses table.

Related

ActiveRecord query for multiple has_many associactions

Using Rails 3.2 I have the following models:
class Category < ActiveRecord::Base
has_many: posts
end
class Post < ActiveRecord::Base
belongs_to :category
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
I'm now looking for a query to find all comments belonging to a certain category.
I would do a join query like this:
Comment.joins(:post=>:category).where("categories.id = ?", category)
One thing to note is the memory usage. If you have lots of fields in comment, post and category and lots of records its not going to be pretty. So use select to specify the fields you need.

Should I use an ActiveRecord has_may-through relation, or a method fetching related items?

I have a FormResponse which belongs_to a Form; the Form then has_many Questions:
class FormResponse < ActiveRecord::Base
belongs_to :form
end
class Form < ActiveRecord::Base
has_many :form_responses
has_many :questions
end
class Question < ActiveRecord::Base
end
When I find myself needing questions in the context of a form, a lot, I prefer to call questions on FormResponse, like so:
form_response = FormResponse.find(id)
form_response.questions
In order to make questions avaiable, I can do this in ActiveRecord:
class FormResponse < ActiveRecord::Base
belongs_to :form
has_many :questions, :through => :form
end
or with an instant-method:
class FormResponse < ActiveRecord::Base
belongs_to :form
def questions
self.form.questions unless self.form.nil?
end
end
I am not interested in setting questions on FormResponse (I won't need
things like FormResponse.questions << or
FormResponse.questions.build), just the fetching.
What are the benefits of using the has_many :questions, :through =>
:form over using a method, and vice-versa? Are there benefits like like lazy-loading, better
SQL and so on?
Does AR give any rules of thumb on when to use an AR-relation and when
to simply write your own methods?
I think this is more a question of encapsulation then of ActiveRecord.
In general I would apply I rule of thumb here:
Use has_many :through when you actually want to model a relation.
Implement a delegation method when all you want to do is not violating the Law of Demeter or keeping your code DRY.

Rails 3 - associations "through" - how to get the data from DB?

I have a problem with fetching data from DB, where is between models association kind through.
On my site, I have a categories, like a sports, news, weather etc. When an user is logged in and has a selected the categories, from which want to see the articles, then I would like to display only these articles.
Here's how looks like my models:
class User < ActiveRecord::Base
has_many :user_categories
has_many :categories, :through => :user_categories
end
class Category < ActiveRecord::Base
has_many :articles
has_many :user_categories
has_many :users, :through => :user_categories
end
class UserCategory < ActiveRecord::Base
belongs_to :user
belongs_to :category
end
class Article < ActiveRecord::Base
belongs_to :category
end
But I still can't find the way, how to get all articles from user's selected categories... I tried something like
Article.joins("LEFT JOIN categories ON category.id = user_categories.category_id").where('user_categories.user_id = ?', current_user.id)
I would grateful for every advice!
Thank you
Here's one way to do it:
Article.where(:category_id => current_user.categories.map {|c| c.id})
That will create 2 queries. First one will return a list of the current user's categories. Then the ruby map function will create an array containing the ids of those categories. The second query will then return a list of articles whose category_id is in the array of ids. The second query will look something like:
select articles.* from articles where articles.category_id in(1,2,3);

Multiple Associations between the same model in Rails

I am working on QA site where I have a Question model and an Answer model and the association between them is like
class Question < ActiveRecord::Base
has_many :answers
end
My answers model is
class Answer < ActiveRecord::Base
belongs_to :question
end
Now I need to create another association between question and answer where I can access the one answer the author of the question finds the best. So what I need is something like
class Question < ActiveRecord::Base
has_many :answers
has_one :accepted_answer, :class_name => 'Answer', :foreign_key => ['answer_id, accepted']
end
This association fails rightly as I have no way of specifying that I expect accepted to be true and I get a MySQL error. Is there a way I can get this to work while using a boolean as composite foreign key?
MySQL server version for the right syntax to use near '["answer_id", "accepted"] = 30) LIMIT 1' at line 1: SELECT `answers`.* FROM `answers` WHERE (`answers`.["answer_id", "accepted"] = 30)
The solution that I have currently employed is creating an association from answers to Question as follows
class Answer < ActiveRecord::Base
belongs_to :question
has_one :inverse_accepted_answer, :class_name => 'Question', :foreign_key => 'accepted_id'
end
and for Question as
Class Question < ActiveRecord::Base
belongs_to :answer, :foreign_key => 'accepted_id'
has_many :answers
end
The problem is in this case i access the selected answer as Question.find(10).answer instead of using a more expressive name as selected_answer.
Is there a way i can define a name for the relationship from the belongs_to end. Secondly what would be the right way to go about this. I technique seems to round about to correct
I am using Rails 3 and Ruby 1.9.2
Thanks in advance
what about something like that:
has_one :accepted_answer, :class_name => 'Answer', :conditions => "accepted = true"

how do I write that join query with ActiveRecord?

anyone know how I would write that query with AR?
select *, (m.user_id=1) as member from band b join memberships m on m.band_id = g.id;
Thanks in advance.
The assumption here is that you have something that looks like this:
class Band < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
class User < ActiveRecord::Base
has_many :memberships
has_many :bands, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :band
end
In which case, you can perform this query easily.
user = User.find(1)
user.bands
Your question is quite vague, however, so if this isn't what you're looking for please considering expanding your question with some more details. You are also referencing an alias "g" in your question which is never defined.
I don't see why you would want to set boolean attributes via the SQL queries. You can do this with good ol' Ruby, which also lets you use has many through as jdl said.
class Book
def member?
user_id == 1
end
end