Reputation: 273
I've been a programmer for a few years (I've mainly used PHP / CakePHP) but I'm new to Ruby on Rails.
I have a question regarding retrieving data for multiple associations with conditions.
I have the following four models:
class Questionnaire < ApplicationRecord
has_many :sections
end
class Section < ApplicationRecord
belongs_to :questionnaire
has_many :questions
has_many :non_questions
def elements
(questions + non_questions).sort_by(&:order)
end
end
class Question < ApplicationRecord
belongs_to :section
validates_date :starts_on, allow_blank: true
validates_date :expires_on, allow_blank: true
end
class NonQuestion < ApplicationRecord
belongs_to :section
end
I currently want to show the whole questionnaire in the view - that is all the sections with their questions and non_questions in one page and in the right order. I would also like to pass a date parameter from the view, which will be used to retrieve the corresponding active questions only, based on the starts_on and expires_on date columns.
Using CakePHP, I would preload and store all the data in a variable in my model by using Left Joins with conditions. I tried to do something similar with rails (using all possible combinations of joins, includes, left_outer_joins) with a where condition, but when I, for example, call questionnaire.sections.first.elements
it runs a new query without applying my condition. Am I missing something out? Is there a "right", ruby way to do something like this? Or given what my application requires, is there a better way to approach this?
Thanks in advance
Upvotes: 3
Views: 80
Reputation: 3398
For eager loader in rails, you use includes
. For your models, for example, you could do something like:
Questionnaire.includes(sections: [:questions, :non_questions]).references(:question).where("(questions.expires_on >= :time OR questions.expires_on IS NULL) AND (questions.starts_on IS NULL OR questionsstarts_on <= :time)" , time: Time.now)
If you want to access that set of records you retrieved multiple times, you should assign then to some variable, so it doesn't make a new query on db. Hope it enlightened your question
Upvotes: 1
Reputation: 23671
Something like
Questionnaire.includes(
sections: [:questions, :non_questions]
).where("questions.starts_on <= :time AND questions.expires_on > :time", time: Time.now)
Upvotes: 0