【问题标题】:Can you do greater than comparison on a date in a Rails 3 search?您可以在 Rails 3 搜索中对日期进行比较吗?
【发布时间】:2011-05-12 14:17:48
【问题描述】:

我在 Rails 3 中有这个搜索:

Note.where(:user_id => current_user.id, :notetype => p[:note_type], :date => p[:date]).order('date ASC, created_at ASC')

但我需要 :date => p[:date] 条件等同于 :date > p[:date]。我怎样才能做到这一点?感谢阅读。

【问题讨论】:

    标签: ruby-on-rails activerecord ruby-on-rails-3


    【解决方案1】:
    Note.
      where(:user_id => current_user.id, :notetype => p[:note_type]).
      where("date > ?", p[:date]).
      order('date ASC, created_at ASC')
    

    或者您也可以将所有内容转换为 SQL 表示法

    Note.
      where("user_id = ? AND notetype = ? AND date > ?", current_user.id, p[:note_type], p[:date]).
      order('date ASC, created_at ASC')
    

    【讨论】:

    • 安全吗?我的意思是如果 p[:date] 来自用户输入,它会导致 SQL 注入吗?
    • 因为where()所以很安全。使用where() 会自动转义输入。
    • Simone 的评论并不完全正确; where() 以上面显示的格式使用输入时自动转义输入,用问号代替变量,然后在函数调用中列出它们。以这种方式使用它是不安全的:Note.where("date > #{p[:date]}")
    • 另外值得注意的是,在合并具有user_id 字段的模型的情况下,使用where("user_id = ?",current_user.id)where(user_id: current_user.id) 风险更大。使用原始 SQL 表示法意味着您需要自己包含表格说明,例如:where("notes.user_id = ?",current_user.id)
    • 你应该小心这个,因为时区。当你使用 where with "" Rails 直接进入数据库,并且在数据库中日期以 UTC 格式保存,但你应该以 UTC + 5 为例,这是不正确的。因此,请确保在执行之前将 p[date] 转换为您当前的 UTC
    【解决方案2】:

    如果遇到列名不明确的问题,您可以这样做:

    date_field = Note.arel_table[:date]
    Note.where(user_id: current_user.id, notetype: p[:note_type]).
         where(date_field.gt(p[:date])).
         order(date_field.asc(), Note.arel_table[:created_at].asc())
    

    【讨论】:

    • 由于某种原因,我在 PostgreSQL 服务器上使用 Simone 的“where”方法找不到列时出现错误,但它在 SQLite 中有效。你的方法对两者都有效。
    【解决方案3】:

    你可以尝试使用:

    where(date: p[:date]..Float::INFINITY)
    

    等价于sql

    WHERE (`date` >= p[:date])
    

    结果是:

    Note.where(user_id: current_user.id, notetype: p[:note_type], date: p[:date]..Float::INFINITY).order(:fecha, :created_at)
    

    我也变了

    order('date ASC, created_at ASC')
    

    对于

    order(:fecha, :created_at)
    

    【讨论】:

      【解决方案4】:

      如果您不喜欢传入字符串,我更喜欢@sesperanto 的做法,除了让它更简洁之外,您可以将Float::INFINITY 放在日期范围内,而只需使用created_at: p[:date]..

      Note.where(
          user_id: current_user.id,
          notetype: p[:note_type],
          created_at: p[:date]..
      ).order(:date, :created_at)
      

      请注意,这会将查询更改为 >= 而不是 >。如果这是一个问题,您总是可以通过运行 p[:date] + 1.day.. 之类的东西来为日期添加一个时间单位

      【讨论】:

        【解决方案5】:

        更新

        Rails 核心团队决定暂时恢复此更改,以便更详细地讨论它。请参阅this commentthis PR 了解更多信息。

        我仅出于教育目的而留下我的答案。


        Rails 6.1 中用于比较的新“语法”(已还原)

        Rails 6.1where 条件下的比较运算符添加了新的“语法”,例如:

        Post.where('id >': 9)
        Post.where('id >=': 9)
        Post.where('id <': 3)
        Post.where('id <=': 3)
        

        所以你的查询可以改写如下:

        Note
          .where(user_id: current_user.id, notetype: p[:note_type], 'date >', p[:date])
          .order(date: :asc, created_at: :asc)
        

        这里是a link to PR,您可以在其中找到更多示例。

        【讨论】:

        • PR 已恢复,因此这在 Rails 中暂时不起作用。 new PR 目前正在进行中。
        • 谢谢,@PaulB。我已经更新了我的答案。
        猜你喜欢
        • 1970-01-01
        • 2013-05-03
        • 2018-02-04
        • 1970-01-01
        • 2014-11-25
        • 2016-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多