Cách chọn ID trong Array Rails ActiveRecord mà không có ngoại lệ


134

Khi tôi có mảng id, như

ids = [2,3,5]

và tôi thực hiện

Comment.find(ids)

mọi thứ đều hoạt động tốt. Nhưng khi có id không tồn tại, tôi nhận được một ngoại lệ. Điều này xảy ra khi tôi nhận được danh sách ID phù hợp với một số bộ lọc và hơn là tôi làm một cái gì đó như

current_user.comments.find(ids)

Lần này tôi có thể có ID nhận xét hợp lệ, tuy nhiên không thuộc về Người dùng cụ thể, vì vậy nó không được tìm thấy và tôi nhận được một ngoại lệ.

Tôi đã thử find(:all, ids), nhưng nó trả về tất cả các hồ sơ.

Cách duy nhất tôi có thể làm bây giờ là

current_user.comments.select { |c| ids.include?(c.id) }

Nhưng đó dường như là giải pháp siêu kém hiệu quả.

Có cách nào tốt hơn để chọn ID trong Mảng mà không có ngoại lệ đối với bản ghi không tồn tại không?

Câu trả lời:


215

Nếu nó chỉ tránh ngoại lệ mà bạn lo lắng, thì nhóm chức năng "find_all_by .." hoạt động mà không cần ném ngoại lệ.

Comment.find_all_by_id([2, 3, 5])

sẽ hoạt động ngay cả khi một số id không tồn tại. Cái này hoạt động trong

user.comments.find_all_by_id(potentially_nonexistent_ids)

trường hợp là tốt.

Cập nhật: Đường ray 4

Comment.where(id: [2, 3, 5])

đây là giải pháp ưa thích của tôi, nó có vẻ sạch hơn tuyến xử lý ngoại lệ
Sam Saffron

5
Là một tiện ích mở rộng khác, nếu bạn cần xâu chuỗi các điều kiện phức tạp, bạn thậm chí có thể thực hiện Comment.all (: condition => ["được phê duyệt và id trong (?)", [1,2,3]])
Omar Qureshi

14
điều này sẽ không được chấp nhận trong Rails 4: edgeguides.rubyonrails.org/ Khăn
Jonathan Lin

3
@JonathanLin là chính xác, câu trả lời của mjnissim nên được ưu tiên: stackoverflow.com/a/11457025/33226
Gavin Miller

6
Điều này trả về một Arraythay vì một ActiveRecord::Relation, giới hạn những gì bạn có thể làm với nó sau đó. Comment.where(id: [2, 3, 5])không trả lại một ActiveRecord::Relation.
Joshua Pinter

147

Cập nhật: Câu trả lời này phù hợp hơn với Rails 4.x

Làm cái này:

current_user.comments.where(:id=>[123,"456","Michael Jackson"])

Mặt mạnh hơn của phương pháp này là nó trả về một Relationđối tượng, mà bạn có thể tham gia nhiều .wheremệnh đề, .limitmệnh đề, v.v., rất hữu ích. Nó cũng cho phép ID không tồn tại mà không ném ngoại lệ.

Cú pháp Ruby mới hơn sẽ là:

current_user.comments.where(id: [123, "456", "Michael Jackson"])

Cảm ơn đã xác nhận wherecú pháp khi so sánh với một mảng. Tôi nghĩ rằng tôi có thể phải viết mã SQL bằng một INcâu lệnh, nhưng điều này có vẻ sạch hơn và là một sự thay thế dễ dàng cho sự phản đối scoped_by_id.
Mark Berry

1
Cái này được gọi là gì và nó hoạt động như thế nào? Có phải là ma thuật Rails?! Như một đồng nghiệp đã nhận xét, nó giống như 'so sánh một số nguyên với một danh sách đối tượng ".
vào

22

Nếu bạn cần kiểm soát nhiều hơn (có lẽ bạn cần nêu tên bảng), bạn cũng có thể làm như sau:

Model.joins(:another_model_table_name)
  .where('another_model_table_name.id IN (?)', your_id_array)

Chính xác những gì tôi đang tìm kiếm. Cảm ơn!
Myxtic

Có cách nào để giữ trật tự your_id_arraykhi bạn lấy lại đồ vật không?
Joshua Pinter

@JoshPinter Tôi không nghĩ rằng đây là một cách đáng tin cậy để mong đợi cơ sở dữ liệu trả lại mọi thứ theo cùng một thứ tự. Có lẽ thêm một truy vấn ORDER BY ở cuối để đảm bảo đúng thứ tự của mọi thứ.
Jonathan Lin

@JonathanLin Cảm ơn bạn đã trả lời Jonathan. Bạn chắc chắn đúng. Sử dụng ORDER BYsẽ không hoạt động trong tình huống của tôi vì thứ tự không dựa trên một thuộc tính. Tuy nhiên, có một cách để làm điều đó thông qua SQL (vì vậy nó rất nhanh) và ai đó thậm chí đã tạo ra một viên ngọc cho nó. Kiểm tra Hỏi & Đáp này: stackoverflow.com/questions/801824/ từ
Joshua Pinter

10

Bây giờ các phương thức .find và .find_by_id không được dùng trong rails 4. Vì vậy, thay vào đó chúng ta có thể sử dụng bên dưới:

Comment.where(id: [2, 3, 5])

Nó sẽ hoạt động ngay cả khi một số id không tồn tại. Cái này hoạt động trong

user.comments.where(id: avoided_ids_array)

Ngoài ra để loại trừ ID

Comment.where.not(id: [2, 3, 5])

3
github.com/rails/activerecord-deprecated_finder .find và .find_by_id không được phản đối trong các đường ray 4.
Canna

0

Để tránh các ngoại lệ giết chết ứng dụng của bạn, bạn nên nắm bắt các ngoại lệ đó và xử lý chúng theo cách bạn muốn, xác định hành vi cho ứng dụng của bạn trong những tình huống không tìm thấy id.

begin
  current_user.comments.find(ids)
rescue
  #do something in case of exception found
end

Dưới đây là thông tin thêm về các ngoại lệ trong ruby.


1
vâng điều này giải quyết vấn đề, nhưng nó không thực sự là một giải pháp sạch
Jakub Arnold

3
Nếu bạn định bắt một ngoại lệ, bạn nên khai báo ngoại lệ mà bạn muốn bắt, nếu không, bạn có nguy cơ bắt được một thứ bạn không mong đợi và che giấu một vấn đề thực tế.
Haegin

0

Bạn cũng có thể sử dụng nó trong tên_scope nếu bạn muốn đặt điều kiện khác

ví dụ bao gồm một số mô hình khác:

tên_scope 'get_by_ids', lambda {| ids | {: bao gồm => [: ý kiến] ,: điều kiện => ["bình luận.id IN (?)", ids]}}

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.