2

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.

0

2 Answers 2

4

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
Sign up to request clarification or add additional context in comments.

1 Comment

I am learning a text book. Please have a look at books.google.co.in/…
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.