2013-08-06 60 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。由于它不是布尔方法,所以最终不应该使用'?'。 –

相关问题