Reputation: 6918
In my User model class, I have defined 2 scopes as given below.
scope :condition, lambda { where('updated_at >= ?', 3.day.ago) }
scope :tardy, lambda {
joins(:timesheets).group("users.id") & Timesheet.condition
}
Then I tried running reload!, and thereafter u =User.find 14 and I got result below.
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 14 LIMIT 1
=> #<User id: 14, login: "janu", password: "janu", password_confirmation: nil, email: "[email protected]", created_at: "2013-01-03 09:47:36", updated_at: "2013-01-03 09:47:36">
Then I run, u.tardy.to_sql,but, it returns the following error.
NoMethodError: undefined method `tardy' for #<User:0x00000003cb5ea0>
from /home/local/rajesh.co/.rvm/gems/ruby-1.9.3-p327/gems/activemodel-3.2.9/lib/active_model/attribute_methods.rb:407:in `method_missing'
from /home/local/rajesh.co/.rvm/gems/ruby-1.9.3-p327/gems/activerecord-3.2.9/lib/active_record/attribute_methods.rb:149:in `method_missing'
from (irb):64
from /home/local/rajesh.co/.rvm/gems/ruby-1.9.3-p327/gems/railties-3.2.9/lib/rails/commands/console.rb:47:in `start'
from /home/local/rajesh.co/.rvm/gems/ruby-1.9.3-p327/gems/railties-3.2.9/lib/rails/commands/console.rb:8:in `start'
from /home/local/rajesh.co/.rvm/gems/ruby-1.9.3-p327/gems/railties-3.2.9/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
See, When I join both the scopes together as given below, then also I am getting the same error.
scope :tardy, lambda {
joins(:timesheets).
where("timesheets.updated_at >= ?", 3.days.ago).
group("users.id")
}
Can you please help me to resolve the same. Thank you.
Upvotes: 2
Views: 1482
Reputation: 6918
The error was on the model's scope definition and meagar's answer is also right for one of the errors.
scope :tardy, lambda {
joins(:timesheets).group("users.id") && Timesheet.condition
}
In the above, I have specified Timesheet.condition where the condition scope has to be declared in the Timesheet model instead of User model since I need to group the users with respect to the time of timesheet updates. So the below given scope has to be there in the Timesheet model like below.
scope :condition, lambda { where('updated_at >= ?', 3.day.ago) }
Run User.tardy, we will get the Users who all are updated their timesheets meeting the condition given.
2nd & Easy way to achieve this is to define a single scope in User model itself:
scope :tardy, lambda {
joins(:timesheets).
where("timesheets.updated_at >= ?", 3.days.ago).
group("users.id")
}
But, this cross-model scope violates good object-oriented design principles: it contains the logic for determining whether or not a Timesheet is updated, which is code that properly belongs in the Timesheet class. So 1st method is preferable.
Thank you all.
Upvotes: 1
Reputation: 239382
You can't invoke a scope on a specific record. When you invoke .find
, you're getting one specific record back, not a relation/association to which additional scopes can be chained.
If you want to find any tardy user with id 14, you'll have to reverse the order of method calls:
User.tardy.find(14)
You still won't be able to run .to_sql
, as you'll again have a single record. If you really want the SQL back for a specific find-by-id, you could use
User.tardy.where(:id => 14).to_sql
Upvotes: 4