如何访问Rails中的记录属性.where()

时间:2017-05-05 10:47:56

标签: ruby-on-rails

如何在.where()中访问对象的属性?

我正在尝试运行这行代码:

Task.where("(created_at <= ?", Time.now - <deadline>).update_all(expired: true)

这个想法是,任何创建日期超过设定截止日期(现在时间 - 截止日期)的任务都会将其expire属性设置为true。

问题是:deadline是Task的一个属性,每个任务都有自己的截止日期。所以我需要.where()检查以下逻辑:对于任何给定的Task对象,如果created_at小于Time.now减去(这是我坚持的部分),而不是设置它已过期属性为true

伪代码:

Task.where( Task's created_at attr is <= to the current time - Tasks's deadline attr ).update_all( set Task's expired attr to true )`

总结:

我需要访问对象的属性作为.where()中逻辑的一部分。

我的其他一些尝试:

  • Task.where("(created_at <= ?", Time.now - :deadline).update_all(expired: true) TypeError:无法将符号转换为确切的数字

  • Task.where("(created_at <= ?", Time.now - self.deadline).update_all(expired: true) NoMethodError:未定义的方法`截止日期&#39; for main:Object

  • Task.where("(created_at <= ?", Time.now - params[:deadline]).update_all(expired: true) NameError:未定义的局部变量或方法`params&#39; for main:Object

编辑:

  create_table "tasks", force: :cascade do |t|
    t.string   "name"
    t.integer  "user_id"
    t.datetime "created_at",                  null: false
    t.datetime "updated_at",                  null: false
    t.boolean  "expired",    default: false
    t.integer  "deadline",   default: 604800
  end

我在开发模式下运行rails,所以我认为数据库是SQL, 截止日期属性应为整数(使用7.days或实际值创建)

2 个答案:

答案 0 :(得分:1)

取决于您的数据库:

对于Postgresql:

date_default_timezone_set('UTC');
$month = date('Ym');
$lastmonth = date('Ym', strtotime('first day of -1 month');

对于MySql:

date_default_timezone_set('UTC');
$dt = new DateTime();
$month = $dt->format('Ym');
$dt2 = $dt; // to save $dt for later use
$lastmonth = $dt2->modify('first day of -1 month')->format('Ym');

SQL Server:

Task.where('created_at + (deadline * "1 second::INTERVAL") <= ?', Time.now)

注意:以上内容未经测试。我只是按照&#34;添加日期功能&#34;的等效语法。对于上面不同的数据库来自各自的文档页面

  • 我不知道任何&#34; ActiveRecord&#34;接近这个。
  • Arel可以正常工作,但在将Task.where('DATE_ADD(created_at, INTERVAL deadline SECOND) <= ?', Time.now) 从秒转换为&#34;持续时间&#34 ;;您可能会找到一种方法来继续以下不完整的表达式:

    Task.where('DATEADD(second, deadline, created_at) <= ?', Time.now)
    

答案 1 :(得分:1)

请记住,解决方案依赖于数据库类型,因此适用于SQLite(如果你已经采用了rails默认值,可能适配器)可能不适用于MySQL或PostgreSQL。例如,如果您决定部署到Heroku,那么您的数据库将是PostgreSQL。

您说您正在为development环境寻找解决方案,所以听起来这是您正在开发但尚未部署的代码?

如果是这样,我建议您更改或更改数据库布局以添加日期时间列expires_at并添加回调方法以在您保存记录时设置它。

class Task < ApplicationRecord
  before_save :update_expires_at
  private
  def update_expires_at
    self.expires_at ||= Time.now + 7.days
  end
end

这会让你做...

Task.where("(expires_at <= ?", Time.now).update_all(expired: true)

但我甚至不确定您是否需要expired列,除非您可能想要将记录设置为手动过期。你可以在课堂上有一个方法......

def expired?
  expires_at <= Time.now
end

您可以为已过期或未过期的

创建范围
class Task < ApplicationRecord

  scope :expired, -> {where('expired_at <= ?', Time.now)}
  scope :active, -> {where('expired_at > ?', Time.now)}

只需使用范围。

@my_expired_tasks = Task.expired