2

在我的用户模型类中,我定义了 2 个范围,如下所示。

  scope :condition, lambda { where('updated_at >= ?', 3.day.ago) }

  scope :tardy, lambda {
    joins(:timesheets).group("users.id") & Timesheet.condition
  }

然后我尝试运行重新加载!,然后u =User.find 14我得到下面的结果。

  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: "janu@gmail.com", created_at: "2013-01-03 09:47:36", updated_at: "2013-01-03 09:47:36"> 

然后我运行u.tardy.to_sql,但是它返回以下错误。

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>'

看,当我如下所示将两个范围连接在一起时,我也会遇到同样的错误。

  scope :tardy, lambda {
    joins(:timesheets).
    where("timesheets.updated_at >= ?", 3.days.ago).
    group("users.id")
  }

你能帮我解决同样的问题吗?谢谢你。

4

2 回答 2

4

您不能在特定记录上调用范围。当您调用 时.find,您将获得一个特定的记录,而不是可以链接到其他范围的关系/关联。

如果你想找到任何 id 为 14 的迟到用户,你必须颠倒方法调用的顺序:

User.tardy.find(14)

仍然无法运行.to_sql,因为您将再次获得一条记录。如果您真的希望 SQL 返回特定的 find-by-id,您可以使用

User.tardy.where(:id => 14).to_sql
于 2013-01-07T04:48:39.470 回答
1

错误出现在模型的范围定义上,meagar 的答案也适用于其中一个错误。

  scope :tardy, lambda {
    joins(:timesheets).group("users.id") && Timesheet.condition
  }

在上面,我指定了Timesheet.condition,其中条件范围必须在Timesheet 模型而不是 User 模型中声明,因为我需要根据时间表更新时间对用户进行分组。因此,下面给定的范围必须存在于 Timesheet 模型中,如下所示。

scope :condition, lambda { where('updated_at >= ?', 3.day.ago) }

运行User.tardy,我们将得到满足给定条件的所有更新时间表的用户。

实现此目的的第二种简单方法是在用户模型本身中定义一个范围:

scope :tardy, lambda {
    joins(:timesheets).
    where("timesheets.updated_at >= ?", 3.days.ago).
    group("users.id")
  }

但是,这种跨模型范围违反了良好的面向对象设计原则:它包含确定是否更新 Timesheet 的逻辑,这是正确属于 Timesheet 类的代码。所以第一种方法更可取。

谢谢你们。

于 2013-01-07T06:14:44.357 回答