find vs find_by vs dimana

127

Saya baru mengenal rel. Apa yang saya lihat ada banyak cara untuk menemukan catatan:

  1. find_by_<columnname>(<columnvalue>)
  2. find(:first, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>).first

Dan sepertinya mereka semua menghasilkan SQL yang persis sama. Juga, saya percaya hal yang sama berlaku untuk menemukan banyak catatan:

  1. find_all_by_<columnname>(<columnvalue>)
  2. find(:all, :conditions => { <columnname> => <columnvalue> }
  3. where(<columnname> => <columnvalue>)

Apakah ada aturan praktis atau rekomendasi yang digunakan?

Victor Ronin
sumber

Jawaban:

103

Gunakan mana pun yang Anda rasa paling sesuai dengan kebutuhan Anda.

The findMetode ini biasanya digunakan untuk mengambil berturut-turut dengan ID:

Model.find(1)

Perlu dicatat bahwa findakan mengeluarkan pengecualian jika item tersebut tidak ditemukan oleh atribut yang Anda berikan. Gunakan where(seperti dijelaskan di bawah ini, yang akan mengembalikan array kosong jika atribut tidak ditemukan) untuk menghindari pengecualian yang dilemparkan.

Kegunaan lain findbiasanya diganti dengan hal-hal seperti ini:

Model.all
Model.first

find_bydigunakan sebagai penolong ketika Anda mencari informasi dalam kolom, dan memetakannya dengan konvensi penamaan. Misalnya, jika Anda memiliki kolom bernama namedi database Anda, Anda akan menggunakan sintaks berikut:

Model.find_by(name: "Bob")

.where lebih merupakan tangkapan semua yang memungkinkan Anda menggunakan logika yang sedikit lebih kompleks untuk ketika pembantu konvensional tidak akan melakukan, dan mengembalikan array item yang cocok dengan kondisi Anda (atau array kosong sebaliknya).

John
sumber
62
find_bytidak ditinggalkan, tetapi sintaks berubah sedikit. Dari find_by_name("Bob")ke find_by(:name, "Bob").
Brian Morearty
61
@BrianMorearty Saya yakin Anda maksudfind_by(name: "Bob")
MCB
1
@BrianMorearty Saya tidak dapat menemukan bukti bahwa find_by_...ia sudah usang, apakah Anda memiliki sumber? Tampaknya find_bydan find_by_...keduanya masih didukung di Rails 4.
Dennis
4
@ Dennis, Anda benar bahwa itu tidak usang, dan itulah yang saya katakan. Tapi saya bisa lebih jelas ketika saya mengatakan "tapi sintaksnya sedikit berubah." Yang saya maksudkan adalah, "tetapi sintaks baru juga tersedia sekarang." Lihat koreksi MCB untuk sintaks baru.
Brian Morearty
3
Inilah yang disebutkan dalam rilis rails 4.0 "Semua metode dinamis kecuali untuk find_by _... dan find_by _...! Tidak digunakan lagi" lebih detail dari edgeguides.rubyonrails.org/...
Mukesh Singh Rathaur
131

di mana mengembalikan ActiveRecord :: Relation

Sekarang lihat implementasi find_by:

def find_by
  where(*args).take
end

Seperti yang Anda lihat, find_by sama dengan di mana tetapi hanya mengembalikan satu catatan. Metode ini harus digunakan untuk mendapatkan 1 catatan dan di mana harus digunakan untuk mendapatkan semua catatan dengan beberapa syarat.

Mike Andrianov
sumber
1
find_by mengembalikan objek, namun mengembalikan koleksi.
Tendang Buttowski
Ketika nilai kueri di luar kisaran, find_byakan menyelamatkan ::RangeErrordari where(*args) dan mengembalikan nol.
Fangxing
34

Model.find

1- Parameter: ID objek yang akan ditemukan.

2- Jika ditemukan: Ini mengembalikan objek (Satu objek saja).

3 - Jika tidak ditemukan: menimbulkan ActiveRecord::RecordNotFoundpengecualian.

Model.find_by

1- Parameter: kunci / nilai

Contoh:

User.find_by name: 'John', email: '[email protected]'

2- Jika ditemukan: Ini mengembalikan objek.

3 - Jika tidak ditemukan: kembali nil.

Catatan: Jika Anda ingin meningkatkanActiveRecord::RecordNotFoundpenggunaanfind_by!

Model.where

1- Parameter: sama dengan find_by

2- Jika ditemukan: Ini mengembalikan ActiveRecord::Relationberisi satu atau lebih catatan yang cocok dengan parameter.

3 - Jika tidak ditemukan: Ini mengembalikan Kosong ActiveRecord::Relation.

Hossam Khamis
sumber
31

Ada perbedaan antara finddan find_byyang findakan mengembalikan kesalahan jika tidak ditemukan, sedangkan find_byakan mengembalikan nol.

Terkadang lebih mudah dibaca jika Anda memiliki metode seperti find_by email: "haha", sebagai lawan .where(email: some_params).first.

Kasumi
sumber
17

Karena Rails 4 dapat Anda lakukan:

User.find_by(name: 'Bob')

yang setara find_by_namedengan Rails 3.

Gunakan #wheresaat #finddan #find_bytidak cukup.

Agis
sumber
2
Agis, saya setuju dengan Anda tetapi saya sudah mencari di internet bahwa mengapa kita harus menggunakan find_bydan tidak find_by_<column_name>. Saya membutuhkannya untuk menjawab seseorang.
KULKING
Agis, apakah Anda memiliki sumber untuk mendukung klaim Anda bahwa kami seharusnya tidak lagi menggunakan find_by_namedalam Rails 4? Sejauh yang saya tahu, itu tidak ditinggalkan .
Dennis
Apakah ada cara sederhana untuk melakukan itu tetapi katakanlah namanya memiliki wildcard di dalamnya jadi sesuatu sepertifind_by(name: "Rob*")
Batman
1
@ Dennis Ini mungkin untuk menggunakan keduanya, mereka valid. Saya lebih suka sintaks baru karena API adalah IMHO lebih intuitif. Begitulah cara saya mendesainnya sendiri :)
Agis
8

Jawaban yang diterima umumnya mencakup semuanya, tetapi saya ingin menambahkan sesuatu, hanya jika Anda berencana untuk bekerja dengan model dengan cara seperti memperbarui, dan Anda sedang mengambil satu catatan (yang idAnda tidak tahu), Lalu find_byapakah cara untuk pergi, karena itu mengambil catatan dan tidak memasukkannya ke dalam array

irb(main):037:0> @kit = Kit.find_by(number: "3456")
  Kit Load (0.9ms)  SELECT "kits".* FROM "kits" WHERE "kits"."number" = 
 '3456' LIMIT 1
=> #<Kit id: 1, number: "3456", created_at: "2015-05-12 06:10:56",   
updated_at: "2015-05-12 06:10:56", job_id: nil>

irb(main):038:0> @kit.update(job_id: 2)
(0.2ms)  BEGIN Kit Exists (0.4ms)  SELECT 1 AS one FROM "kits" WHERE  
("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.5ms)   
UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE  "kits"."id" = 
1  [["job_id", 2], ["updated_at", Tue, 12 May 2015 07:16:58 UTC +00:00]] 
(0.6ms)  COMMIT => true

tetapi jika Anda menggunakan wheremaka Anda tidak dapat memperbaruinya secara langsung

irb(main):039:0> @kit = Kit.where(number: "3456")
Kit Load (1.2ms)  SELECT "kits".* FROM "kits" WHERE "kits"."number" =  
'3456' => #<ActiveRecord::Relation [#<Kit id: 1, number: "3456", 
created_at: "2015-05-12 06:10:56", updated_at: "2015-05-12 07:16:58", 
job_id: 2>]>

irb(main):040:0> @kit.update(job_id: 3)
ArgumentError: wrong number of arguments (1 for 2)

dalam kasus seperti itu Anda harus menentukannya seperti ini

irb(main):043:0> @kit[0].update(job_id: 3)
(0.2ms)  BEGIN Kit Exists (0.6ms)  SELECT 1 AS one FROM "kits" WHERE 
("kits"."number" = '3456' AND "kits"."id" != 1) LIMIT 1 SQL (0.6ms)   
UPDATE "kits" SET "job_id" = $1, "updated_at" = $2 WHERE "kits"."id" = 1  
[["job_id", 3], ["updated_at", Tue, 12 May 2015 07:28:04 UTC +00:00]]
(0.5ms)  COMMIT => true
Leonard Kakande
sumber
persis apa yang saya cari
Paul Brunache
2
@kit = Kit.where (nomor: "3456"). pertama - Ini memungkinkan Anda memperbaruinya secara langsung dan lebih aman karena selamat dari
penghinaan
6

Selain jawaban yang diterima, mengikuti juga valid

Model.find()dapat menerima berbagai nomor id, dan akan mengembalikan semua catatan yang cocok. Model.find_by_id(123)juga menerima array tetapi hanya akan memproses nilai id pertama yang ada dalam array

Model.find([1,2,3])
Model.find_by_id([1,2,3])
Saumya Mehta
sumber
3

Jawaban yang diberikan sejauh ini semuanya OK.

Namun, satu perbedaan yang menarik adalah Model.findpencarian berdasarkan id; jika ditemukan, ia mengembalikan Modelobjek (hanya satu catatan) tetapi melempar yang ActiveRecord::RecordNotFoundsebaliknya.

Model.find_bysangat mirip dengan Model.finddan memungkinkan Anda mencari kolom atau grup kolom apa pun di basis data Anda tetapi itu kembali niljika tidak ada catatan yang cocok dengan pencarian.

Model.wheredi sisi lain mengembalikan Model::ActiveRecord_Relationobjek yang sama seperti array yang berisi semua catatan yang cocok dengan pencarian . Jika tidak ada catatan yang ditemukan, itu mengembalikan Model::ActiveRecord_Relationobjek kosong .

Saya harap ini akan membantu Anda dalam memutuskan mana yang akan digunakan kapan saja.

eselon
sumber
3

Misalkan saya punya model User

  1. User.find(id)

Mengembalikan baris di mana kunci utama = id. Jenis pengembalian akan menjadi Userobjek.

  1. User.find_by(email:"[email protected]")

Mengembalikan baris pertama dengan atribut yang cocok atau email dalam kasus ini. Jenis pengembalian akan menjadi Userobjek lagi.

Catatan: - User.find_by(email: "[email protected]")mirip denganUser.find_by_email("[email protected]")

  1. User.where(project_id:1)

Mengembalikan semua pengguna di tabel pengguna tempat atribut cocok.

Di sini tipe pengembalian akan menjadi ActiveRecord::Relationobjek. ActiveRecord::Relationkelas termasuk Enumerablemodul Ruby sehingga Anda dapat menggunakan objeknya seperti array dan melewatinya.

Nikhil Mohadikar
sumber
0

Bagian terbaik dari bekerja dengan teknologi open source adalah Anda dapat memeriksa panjang dan luasnya. Lihat tautan ini

find_by ~> Menemukan catatan pertama yang cocok dengan kondisi yang ditentukan. Tidak ada pemesanan tersirat jadi jika pesanan penting, Anda harus menentukannya sendiri. Jika tidak ada catatan yang ditemukan, mengembalikan nihil.

find ~> Menemukan catatan pertama yang cocok dengan kondisi yang ditentukan, tetapi jika tidak ada catatan yang ditemukan, itu menimbulkan pengecualian tetapi itu dilakukan dengan sengaja.

Lakukan checkout pada tautan di atas, ia memiliki semua penjelasan dan menggunakan case untuk dua fungsi berikut.

Nshank
sumber
-5

Saya pribadi akan merekomendasikan menggunakan

where(< columnname> => < columnvalue>)
Prateek Alakh
sumber
1
Ini mungkin menjawab pertanyaan. Tetapi coba gambarkan pro dan kontra dari menggunakan pendekatan Anda, alih-alih jawaban yang diterima.
Vivek Kumar