2013-08-06 63 views
38

檢查數據庫在處理之前是否會返回記錄的最有效方法是什麼?例如:Truck.where("id = ?", id).select('truck_no').first.truck_noRails檢查數據庫中是否存在記錄

如果卡車存在,這可能會也可能不會返回卡車。處理此請求時,確保頁面不會崩潰的最有效方法是什麼?如果我可以說我正在使用一個循環遍歷每輛卡車並打印出它的編號,我將如何在視圖和控制器中處理這個問題。

如果記錄不存在,我希望能夠打印出消息,而不是說找不到記錄。

+0

哪個版本是你嗎? – Shaunak

+2

看看是否存在?方法http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F – cristian

回答

36

這裏是你如何檢查這個。

if Trucks.where(:id => current_truck.id).blank? 
    # no truck record for this id 
else 
    # at least 1 record for this truck 
end 

其中方法返回的ActiveRecord :: Relation對象(像它包含其中的結果的行爲陣列),它可以是空的,但從來沒有爲零。

+0

我一直以爲它會返回一個零。謝謝澄清。 – Bojan

+0

@無論誰只是低估了它。請添加評論,所以它有助於理解什麼是錯在這裏.. – Shaunak

+5

使用'存在?'空白的'insetad?'。這將執行查詢來檢查數據庫中是否存在對象,而不是檢索整個對象。 –

1

你可能只是做:

@truck_no = Truck.where("id = ?", id).pluck(:truck_no).first 

這將返回nil如果沒有找到記錄,或者truck_no只有第一個記錄,否則。

那麼在你看來,你可能只是這樣做:

<%= @truck_no || "There are no truck numbers" %> 

如果你想獲取並在控制器顯示多個結果,則:

@truck_nos = Truck.where("id = ?", id).pluck(:truck_no) 

,並在您的視圖:

<% truck_nos.each do |truck_no| %> 
    <%= truck_no %> 
<% end %> 

<%= "No truck numbers to iterate" if truck_nos.blank? %> 
+0

感謝您的建議。我從來不知道採摘方法。 – Bojan

+0

不客氣。 'pluck'將從你的表中選擇一列。 – Agis

8

OP實際使用情況的解決方案

最簡單的解決方案是你的數據庫檢查和檢索數據合併到1找到更多的例子數據庫查詢,而不是分開的數據庫調用。你的示例代碼很接近並傳達了你的意圖,但是在你的實際語法中它有點不合適。

如果你簡單做Truck.where("id = ?", id).select('truck_no').first.truck_no這個記錄不存在,就當你調用truck_no因爲first可以檢索nil記錄,如果沒有找到符合條件的拋出nil錯誤。

這是因爲您的查詢將返回符合條件的對象數組,然後您在該數組上執行first(如果找不到匹配的記錄)爲nil

一個相當乾淨的解決方案:

# Note: using Rails 4/Ruby 2 syntax 
first_truck = Truck.select(:truck_no).find_by(id) # => <Truck id: nil, truck_no: "123"> OR nil if no record matches criteria 

if first_truck 
    truck_number = first_truck.truck_no 
    # do some processing... 
else 
    # record does not exist with that criteria 
end 

我建議用乾淨的語法,「意見」本身讓其他人知道你想要做什麼。

如果你真的要多走一英里,你可以一個方法添加到您的Truck類,這是否對你和傳達你的意圖:

# truck.rb model 
class Truck < ActiveRecord::Base 
    def self.truck_number_if_exists(record_id) 
    record = Truck.select(:truck_no).find_by(record_id) 
    if record 
     record.truck_no 
    else 
     nil # explicit nil so other developers know exactly what's going on 
    end 
    end 
end 

您需要調用它像這樣:

if truck_number = Truck.truck_number_if_exists(id) 
    # do processing because record exists and you have the value 
else 
    # no matching criteria 
end 

ActiveRecord.find_by方法將檢索符合條件的第一條記錄,否則返回nil如果在該條件下未找到記錄。請注意,find_bywhere方法的順序很重要;您必須致電Truck模型上的select。這是因爲當你調用where方法時,你實際上返回了一個ActiveRelation對象,這不是你在這裏尋找的東西。

See ActiveRecord API for 'find_by' method

通用的解決方案使用 '存在?'方法

由於一些其他貢獻者已經提到,exists?方法專門設計用於檢查是否存在某些東西。它不返回值,只是確認數據庫有符合某些條件的記錄。

如果您需要驗證某些數據的唯一性或準確性,這很有用。好的部分是它允許你使用ActiveRelation(Record?) where(...)標準。

舉例來說,如果你有一個User模型與email屬性,你需要檢查的電子郵件中已經存在的分貝:

User.exists?(email: "[email protected]")

使用exists?的好處是SQL查詢運行是

SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1

比實際上返回數據更高效。

如果您需要實際有條件地從數據庫檢索數據,則不是使用的方法。但是,它對於簡單的檢查非常有用,並且語法非常清晰,所以其他開發人員完全知道你在做什麼。使用適當的語法在多個開發人員的項目中非常重要寫乾淨的代碼,並讓代碼「評論」本身。

+2

這是一個非常有用的演練,謝謝 –

+0

在紅寶石任何函數返回true或false,這是'truck_number_if_exists(ID)'你的情況,應該有問號到底 – ImranNaqvi

+0

@ImranNaqvi:你是正確的,因爲約定Ruby是將'?'追加到布爾方法;然而,在這種情況下,'truck_number_if_exist(id)'不是布爾方法;它返回一個值,如果存在,否則返回nil。由於它不是布爾方法,所以最終不應該使用'?'。 –

相關問題