2012-03-17 24 views
13

這已被竊聽我一會兒......我該怎麼做? Model.where( 「created_at> =#{Time.now - 5.days}」)

我怎樣才能串插一個datetime在Rails的ActiveRecord的查詢?

# 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 2012-03-17 08:04:17

+4

「在一桶魚鉤上晃動蘋果」史詩 – 2013-03-29 00:55:08

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

這很漂亮,Mike。 – thewillcole 2013-05-16 23:30:23