2012-03-17 9 views
13

これは、しばらくの間、私を盗聴されています...私は文字列のRailsのActiveRecordクエリでdatetimeを補間することができますどのようにどうすればいいですか? Model.where( "のcreated_at> =#{Time.now - 5.days}")

# Works, but supeh ugleh: 
Model.where("created_at >= ?", Time.now - 5.days) 

# How do I do this? 
Model.where("created_at >= #{Time.now - 5.days}") 
# As is, it produces the following error message: 
# ActiveRecord::StatementInvalid: PG::Error: ERROR: syntax error at or near ... 

私は気にした理由は、コードの読みやすさのためである:

# I like this better: 
Model.where("created_at >= #{Time.now - 5.days} OR" + \ 
      "updated_at >= #{Time.now - 3.days}") 

# than this: 
Model.where("created_at >= ? OR updated_at >= ?", Time.now - 5.days, Time.now - 3.days) 

答えて

56

私はこのために、文字列の補間を使用しないことをお勧めする、そこに多くの鋭いエッジがあり、あなたはおそらく、りんごのためにボビングより多くの楽しみを持っています魚のフックのバケツで。あなたはそれをこのように実行する必要があります(ウェル)使用

Model.where(
    'created_at >= :five_days_ago or updated_at >= :three_days_ago', 
    :five_days_ago => Time.now - 5.days, 
    :three_days_ago => Time.now - 3.days 
) 

という名前のプレースホルダあなたが文字列の補間オファーを考える読みやすさと位置の独立性を与えるが、うまく引用し、タイムゾーンを回避し、あなたの文字列補間軍形式の問題。

しかし、文字列補間はどのように安全に使用しますか?

  1. 引用符で囲んでエスケープする必要があります。
  2. タイムスタンプ形式。
  3. おそらくタイムゾーンです。

ActiveRecordがあなたのためにこのすべてのナンセンスを処理します。

自分で引用符で囲まないでください。ドライバの引用方法を使用してください。文字列を正しく引用するには、connection.quoteにアクセスしてください。

データベースはISO 8601 timestampsと何をするべきかを知っており、便利な方法はiso8601です。 ISO 8601にも便利にタイムゾーンが含まれており、データベースでそれを解析できるはずです(ただし、できない場合は、.utcで時間をUTCに変換する必要があります)。

ので、安全のために:それは

Model.where("created_at >= #{connection.quote((Time.now - 5.days).utc.iso8601)} " + \ 
     "OR updated_at >= #{connection.quote((Time.now - 3.days).utc.iso8601)}") 

ないとてもきれいになりましたでしょうか? ISO 8601を使用すると、単純な単一引用符でconnection.quote通話置き換える安全なはずのタイムスタンプ:

Model.where("created_at >= '#{(Time.now - 5.days).utc.iso8601}' " + \ 
     "OR updated_at >= '#{(Time.now - 3.days).utc.iso8601}'") 

をあなたはまだ、ノイズと醜さをたくさん持っていて、悪い習慣を開発することがあります。

私たちは1999年にPHPプログラマのようなパーティーを行っていないので、SQLで文字列補間を使用して名前付きプレースホルダを使用することで、怠け者ではありません。

+2

と*その*、紳士淑女を、なぜですこの記事の執筆時点では、74.2kの担当者がいます。私はupvoteを一度しか打つことができませんが、本当にあなたの答えの明快さと徹底に感謝します。 – thewillcole

+4

"魚のフックのバケツでリンゴのためのボビング"叙事詩 –

45

古い質問が、私の好む方法は次のとおりです。

Model.where(created_at: 5.days.ago..Time.current) 

多くきれいにし、より読みやすいです。また

Rails 3.2 introducedいくつかのアクティブサポートヘルパー・メソッドは、いくつかの共通の範囲、Time#all_dayTime#all_weekTime#all_quarterTime#all_yearを取得するには、そのインスタンスのために行うことができます:

Model.where(created_at: Time.current.all_week) 
+2

それはかなりドープです、マイク。 – thewillcole

関連する問題