Thanos
Thanos

Reputation: 273

retrieving multiple association data with conditions

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

Answers (2)

Ronan Lopes
Ronan Lopes

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.exp‌​ires_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

Deepak Mahakale
Deepak Mahakale

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

Related Questions