52

データベースがレコードを処理する前に返すかどうかを確認する最も効率的な方法は何ですか。例:Truck.where("id = ?", id).select('truck_no').first.truck_no

トラックが存在する場合、これはトラックを返す場合と返さない場合があります。このリクエストを処理するときにページがクラッシュしないようにするための最も効率的な方法は何ですか? ループを使用して各トラックを通過し、その番号を出力しているとしたら、ビューとコントローラーの両方でこれをどのように処理しますか。

レコードが存在しない場合は、代わりにレコードが見つからないというメッセージを出力できるようにしたいと考えています。

4

6 に答える 6

110

オブジェクトの存在を確認したい場合は、exists を使用してみませんか?

if Truck.exists?(10)
  # your truck exists in the database
else
  # the truck doesn't exist
end

このexists?方法には、データベースからレコードを選択しないという利点があります (つまり、レコードを選択するよりも高速です)。クエリは次のようになります。

SELECT 1 FROM trucks where trucks.id = 10

#exists?の Rails ドキュメントで、さらに多くの例を見つけることができます。.

于 2013-08-06T14:56:53.630 に答える
8

OP 実際のユースケース ソリューション

最も簡単な解決策は、DB 呼び出しを個別に行うのではなく、DB チェックとデータの取得を 1 つの DB クエリに結合することです。サンプル コードは近いものであり、意図を伝えていますが、実際の構文では少しずれています。

単純Truck.where("id = ?", id).select('truck_no').first.truck_noにこのレコードが存在しない場合は、条件に一致するレコードが見つからない場合にレコードを取得する可能性があるため、呼び出しnil時にエラーがスローされます。truck_nofirstnil

これは、クエリが基準に一致するオブジェクトの配列を返すため、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_byおよびwhereメソッドの順序が重要であることに注意してください。モデルselectで を呼び出す必要があります。Truckこれは、メソッドを呼び出すと、ここで探しているものではないオブジェクトwhereが実際に返されるためです。ActiveRelation

「find_by」メソッドについては ActiveRecord API を参照してください

「exists?」を使用した一般的な解決策 方法

他の貢献者の何人かがすでに言及しているように、このexists?メソッドは何かの存在をチェックするために特別に設計されています。値を返すのではなく、DB にいくつかの基準に一致するレコードがあることを確認するだけです。

一部のデータの一意性または正確性を検証する必要がある場合に役立ちます。ActiveRelation(Record?) where(...)良い点は、基準を使用できることです。

たとえばUser、属性を持つモデルがemailあり、電子メールが dB に既に存在するかどうかを確認する必要がある場合:

User.exists?(email: "test@test.com")

を使用する利点はexists?、SQL クエリの実行が

SELECT 1 AS one FROM "users" WHERE "users"."email" = 'test@test.com' LIMIT 1

実際にデータを返すよりも効率的です。

実際に DB から条件付きでデータを取得する必要がある場合、これは使用する方法ではありません。ただし、単純なチェックにはうまく機能し、構文は非常に明確であるため、他の開発者はあなたが何をしているかを正確に知ることができます. 複数の開発者がいるプロジェクトでは、適切な構文を使用することが重要です。きれいなコードを書き、コード自体を「コメント」にします。

于 2014-04-16T12:09:00.920 に答える
0

Railsにはpersisted?好きなように使う方法があります

于 2016-03-19T16:03:16.707 に答える