tìm vs tìm_by vs ở đâu


127

Tôi mới đến đường ray. Những gì tôi thấy rằng có rất nhiều cách để tìm một bản ghi:

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

Và có vẻ như tất cả chúng cuối cùng tạo ra chính xác cùng một SQL. Ngoài ra, tôi tin điều tương tự cũng đúng khi tìm nhiều bản ghi:

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

Có một quy tắc của ngón tay cái hoặc khuyến nghị về việc sử dụng một?

Câu trả lời:


103

Sử dụng bất cứ thứ gì bạn cảm thấy phù hợp với nhu cầu của bạn nhất.

Các findphương pháp thường được sử dụng để lấy một hàng bằng ID:

Model.find(1)

Điều đáng chú ý là findsẽ ném ngoại lệ nếu không tìm thấy vật phẩm bởi thuộc tính mà bạn cung cấp. Sử dụng where(như được mô tả dưới đây, sẽ trả về một mảng trống nếu không tìm thấy thuộc tính) để tránh ngoại lệ bị ném.

Các cách sử dụng khác findthường được thay thế bằng những thứ như thế này:

Model.all
Model.first

find_byđược sử dụng như một người trợ giúp khi bạn đang tìm kiếm thông tin trong một cột và nó ánh xạ tới các quy ước đặt tên. Ví dụ: nếu bạn có một cột có tên nametrong cơ sở dữ liệu của mình, bạn sẽ sử dụng cú pháp sau:

Model.find_by(name: "Bob")

.where nhiều hơn một chút tất cả cho phép bạn sử dụng logic phức tạp hơn một chút khi những người trợ giúp thông thường sẽ không làm và nó trả về một mảng các mặt hàng phù hợp với điều kiện của bạn (hoặc một mảng trống khác).


62
find_bykhông được phản đối, nhưng cú pháp đang thay đổi một chút. Từ find_by_name("Bob")đến find_by(:name, "Bob").
Brian Morearty

61
@BrianMorearty Tôi tin bạn có nghĩa làfind_by(name: "Bob")
MCB

1
@BrianMorearty Tôi không thể tìm thấy bất kỳ bằng chứng nào về find_by_...việc bị từ chối , bạn có nguồn nào không? Dường như find_byfind_by_...cả hai vẫn được hỗ trợ trong Rails 4.
Dennis

4
@Dennis, bạn đúng là nó không được tán thành, và đó là những gì tôi đã nói. Nhưng tôi có thể đã rõ ràng hơn khi tôi nói "nhưng cú pháp đang thay đổi một chút." Ý tôi là "nhưng một cú pháp mới cũng có sẵn." Xem phần sửa lỗi của MCB cho cú pháp mới.
Brian Morearty

3
Đây là những gì được đề cập trong đường ray 4.0 phát hành "Tất cả các phương pháp năng động trừ find_by _... và find_by _... đang bị phản đối!" Thêm chi tiết của edgeguides.rubyonrails.org/...
Mukesh Singh Rathaur

131

nơi trả về ActiveRecord :: Relation

Bây giờ hãy xem thực hiện find_by:

def find_by
  where(*args).take
end

Như bạn có thể thấy find_by giống như ở đâu nhưng nó chỉ trả về một bản ghi. Phương pháp này nên được sử dụng để nhận 1 bản ghi và nơi nên được sử dụng để nhận tất cả các bản ghi với một số điều kiện.


1
find_by trả về một đối tượng, nhưng nơi trả về một bộ sưu tập.
Kick Buttowski

Khi truy vấn giá trị ra khỏi phạm vi, find_bysẽ giải cứu ::RangeErrortừ where(*args) và trở lại con số không.
fangxing

34

Model.find

1- Tham số: ID của đối tượng cần tìm.

2- Nếu tìm thấy: Nó trả về đối tượng (Chỉ một đối tượng).

3- Nếu không tìm thấy: làm tăng ActiveRecord::RecordNotFoundngoại lệ.

Model.find_by

1- Tham số: khóa / giá trị

Thí dụ:

User.find_by name: 'John', email: 'john@doe.com'

2- Nếu tìm thấy: Nó trả về đối tượng.

3- Nếu không tìm thấy: trả về nil.

Lưu ý: Nếu bạn muốn nó tăngActiveRecord::RecordNotFoundsử dụngfind_by!

Model.where

1- Thông số: giống như find_by

2- Nếu tìm thấy: Nó trả về ActiveRecord::Relationchứa một hoặc nhiều bản ghi khớp với các tham số.

3- Nếu không tìm thấy: Nó trả về một sản phẩm nào ActiveRecord::Relation.


31

Có một sự khác biệt giữa findfind_bytrong đó findsẽ trả về một lỗi nếu không tìm thấy, trong khi đó find_bysẽ trả về null.

Đôi khi nó dễ đọc hơn nếu bạn có một phương thức như thế find_by email: "haha", trái ngược với .where(email: some_params).first.


17

Vì Rails 4 bạn có thể làm:

User.find_by(name: 'Bob')

tương đương find_by_nametrong Rails 3.

Sử dụng #wherekhi #find#find_bykhông đủ.


2
Agis, tôi đồng ý với bạn nhưng tôi đã tìm kiếm trên internet rằng tại sao chúng ta nên sử dụng find_byvà không find_by_<column_name>. Tôi cần nó để trả lời một ai đó.
KULKING

Agis, bạn có nguồn nào để sao lưu khiếu nại của mình rằng chúng tôi không còn nên sử dụng find_by_nametrong Rails 4 không? Theo tôi biết, nó không bị phản đối .
Dennis

Có một cách đơn giản để làm điều đó nhưng nói rằng cái tên có ký tự đại diện trong đó sao cho giống nhưfind_by(name: "Rob*")
Batman

1
@Dennis Có thể sử dụng cả hai, chúng đều hợp lệ. Tôi thích cú pháp mới vì API là IMHO trực quan hơn. Đó là cách tôi sẽ tự thiết kế nó :)
Agis

8

Câu trả lời được chấp nhận thường bao gồm tất cả, nhưng tôi muốn thêm một cái gì đó, chỉ cần bạn dự định làm việc với mô hình theo cách như cập nhật và bạn đang truy xuất một bản ghi (mà idbạn không biết), thì đó find_bylà cách để đi, bởi vì nó lấy bản ghi và không đặt nó trong một mảng

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

nhưng nếu bạn sử dụng wherethì bạn không thể cập nhật trực tiếp

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)

trong trường hợp như vậy bạn sẽ phải xác định nó như thế này

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

chính xác những gì tôi đang tìm kiếm
Paul Brunache 7/11/2015

2
@kit = Kit.where (số: "3456"). Đầu tiên - Điều này cho phép bạn cập nhật trực tiếp và an toàn hơn vì nó không còn tồn tại
Paul Brunache

6

Ngoài câu trả lời được chấp nhận, sau đây cũng có giá trị

Model.find()có thể chấp nhận mảng id và sẽ trả về tất cả các bản ghi khớp. Model.find_by_id(123)cũng chấp nhận mảng nhưng sẽ chỉ xử lý giá trị id đầu tiên có trong mảng

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


3

Các câu trả lời cho đến nay đều ổn.

Tuy nhiên, một sự khác biệt thú vị là Model.findtìm kiếm theo id; nếu được tìm thấy, nó sẽ trả về một Modelđối tượng (chỉ là một bản ghi) nhưng ném một cái ActiveRecord::RecordNotFoundkhác.

Model.find_byrất giống với Model.findvà cho phép bạn tìm kiếm bất kỳ cột hoặc nhóm cột nào trong cơ sở dữ liệu của bạn nhưng nó sẽ trả về nilnếu không có bản ghi nào khớp với tìm kiếm.

Model.wheremặt khác trả về một Model::ActiveRecord_Relationđối tượng giống như một mảng chứa tất cả các bản ghi khớp với tìm kiếm . Nếu không tìm thấy bản ghi, nó sẽ trả về một Model::ActiveRecord_Relationđối tượng trống .

Tôi hy vọng những điều này sẽ giúp bạn trong việc quyết định sử dụng bất cứ lúc nào.


3

Giả sử tôi có một mô hình User

  1. User.find(id)

Trả về một hàng trong đó khóa chính = id. Kiểu trả về sẽ là Userđối tượng.

  1. User.find_by(email:"abc@xyz.com")

Trả về hàng đầu tiên với thuộc tính phù hợp hoặc email trong trường hợp này. Kiểu trả về sẽ là Userđối tượng một lần nữa.

Lưu ý: - User.find_by(email: "abc@xyz.com")tương tự nhưUser.find_by_email("abc@xyz.com")

  1. User.where(project_id:1)

Trả về tất cả người dùng trong bảng người dùng nơi khớp thuộc tính.

Ở đây loại trả về sẽ là ActiveRecord::Relationđối tượng. ActiveRecord::Relationlớp bao gồm Enumerablemô-đun của Ruby để bạn có thể sử dụng đối tượng của nó như một mảng và duyệt qua nó.


0

Phần tốt nhất khi làm việc với bất kỳ công nghệ nguồn mở nào là bạn có thể kiểm tra chiều dài và chiều rộng của nó. Kiểm tra liên kết này

find_by ~> Tìm bản ghi đầu tiên khớp với các điều kiện đã chỉ định. Không có ngụ ý đặt hàng vì vậy nếu vấn đề đặt hàng, bạn nên tự xác định nó. Nếu không có bản ghi được tìm thấy, trả về nil.

find ~> Tìm bản ghi đầu tiên phù hợp với các điều kiện đã chỉ định, nhưng nếu không tìm thấy bản ghi nào, nó sẽ phát sinh một ngoại lệ nhưng điều đó được thực hiện có chủ ý.

Hãy kiểm tra các liên kết trên, nó có tất cả các trường hợp giải thích và sử dụng cho hai chức năng sau.


-5

Cá nhân tôi sẽ khuyên bạn nên sử dụng

where(< columnname> => < columnvalue>)

1
Điều này có thể trả lời câu hỏi. Nhưng hãy thử mô tả những ưu và nhược điểm của việc sử dụng phương pháp của bạn, thay vì câu trả lời được chấp nhận.
Vivek Kumar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.