简体   繁体   中英

How to make use of ruby procs to dynamically execute a database query

I have a model called Bucket which has this instance method Bucket#populate_students_academicwise(mentor)

def populate_students_academicwise(mentor)
  student_ids = Mark.find(:all,
    :joins => self.student_current_klass,
    :conditions => ["marks.subject_id = ? AND st.klass_id = ? AND marks.klass_id = ? AND u.account_enabled IS TRUE AND sub.active IS TRUE AND k.active IS TRUE", mentor.subject_id, mentor.klass_id, mentor.klass_id],
    :group => "marks.student_id",
    :having => ["ROUND(AVG(marks_obtained)/AVG(marks_total)*100) BETWEEN ?  AND  ?", min_range, max_range]).collect(&:student_id)

  self.assign_students(student_ids)
end

Now, this query returns a set of students whose academic performance is between a range of values

ROUND(AVG(marks_obtained)/AVG(marks_total)*100) BETWEEN ?  AND  ?)

I call this method from a bucket instance like this bucket.populate_students_academicwise(mentor)

I'd like to negate that query, meaning, return the set of students whose academic performance is NOT between a range of values. All I can think of is to create another method that runs negative of the above query. So I have another method Bucket#negate_populate_students_academicwise(mentor)

def negate_populate_students_academicwise(mentor)
    Mark.find(:all,
      :joins => self.student_current_klass,
      :conditions => ["marks.subject_id = ? AND st.klass_id = ? AND marks.klass_id = ? AND u.account_enabled IS TRUE AND sub.active IS TRUE AND k.active IS TRUE", mentor.subject_id, mentor.klass_id, mentor.klass_id],
      :group => "marks.student_id",
      :having => ["ROUND(AVG(marks_obtained)/AVG(marks_total)*100) NOT BETWEEN ?  AND  ?", min_range, max_range]).collect(&:student_id)
end

Now, this query returns a set of students whose academic performance is NOT between a range of values ROUND(AVG(marks_obtained)/AVG(marks_total)*100) NOT BETWEEN ? AND ? ROUND(AVG(marks_obtained)/AVG(marks_total)*100) NOT BETWEEN ? AND ?

How can I call the first method Bucket#populate_students_academicwise(mentor) with a negate method appended to it bucket.populate_students_academicwise(mentor).negate that would call a proc to negate the query?

So you want to basically have both functionalities and still have them in a DRY way?

I would say you should use a default parameter.

bucket.populate_students_academicwise(mentor) # dont negate
bucket.populate_students_academicwise(mentor,false) # negate

Within you method

def populate_students_academicwise(mentor,in_range = true)
  student_ids = Mark.find(:all,
                   :joins => self.student_current_klass,
                   :conditions => ["marks.subject_id = ? AND st.klass_id = ? AND marks.klass_id = ? AND u.account_enabled IS TRUE AND sub.active IS TRUE AND k.active IS TRUE", mentor.subject_id, mentor.klass_id, mentor.klass_id],
                   :group => "marks.student_id",
                   :having => ["ROUND(AVG(marks_obtained)/AVG(marks_total)*100) #{'NOT' if !in_range} BETWEEN ?  AND  ?", min_range, max_range]).collect(&:student_id)
  self.assign_students(student_ids)
end

With that little bit of query manipulation you get your NOT (or no NOT) depending on the parameter and dont need to worry about proc here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM