Question

Is there a way that I can convert the to_be_approved by method in the following code to be a scope that uses the two other scopes?

scope :reports_to, lambda { |manager| 
  joins(" JOIN admin_users request_user on requests.admin_user_id = request_user.id and request_user.manager_id = #{manager.id} ") }
scope :pending, joins(:admin_request_status).where('admin_request_statuses.name = ?','Pending Approval')

def self.to_be_approved_by( manager )
  reports_to(manager).pending
end

I also want to get rid of the embedded sql in the reports_to scope, but that is a whole different question :)

Was it helpful?

Solution

scope :reports_to, lambda { |manager| joins(:admin_user).where('admin_users.manager_id = ?',manager.id) }  
scope :pending, joins(:admin_request_status).where('admin_request_statuses.name = ?','Pending Approval')
scope :to_be_approved_by, lambda { |manager| self.pending.reports_to(manager) }
end

Note to all.

Chaining scopes like this is usually ok performance-wise because the 'outer' or 'initial' scope will not be evaluated until the full scope chain is called in an example (e.g. scope_name1.scope_name2.scope_name3, etc. and only when the actual output is needed will the sql be constructed. This is known as "lazy loading", e.g. 'Be lazy, don't build results until actually needed".

This is as opposed to "eager loading " where you use the :include statement to get other tables and do mutiple queries "in one go" and avoid an infamous "n+1" problem which is where the program ends up executing (for example) 101 queries to get 100 records.

Lots of fun info :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top