2013-01-22 32 views
9

Tôi có một ứng dụng có một số mô hình Post, mỗi mô hình belongs_to một mô hình User. Khi các bài đăng này được xuất bản, một mô hình PublishedPost được tạo ra belongs_to mô hình Post có liên quan.ActiveRecord: không thể sử dụng `pluck` sau mệnh đề` where` với các liên kết mong muốn

Tôi đang cố gắng tạo truy vấn ActiveRecord để tìm các bài đăng được xuất bản khớp với tên người dùng, sau đó lấy id của các bài đăng được xuất bản đó, nhưng tôi gặp lỗi khi cố gắng sử dụng phương pháp pluck sau khi háo hức- tải các hiệp hội của tôi và tìm kiếm chúng bằng phương pháp where.

Dưới đây là (một phần của) điều khiển của tôi:

class PublishedPostsController < ApplicationController 

    def index 
    ar_query = PublishedPost.order("published_posts.created_at DESC") 

     if params[:searchQuery].present? 
     search_query = params[:searchQuery] 
     ar_query = ar_query.includes(:post => :user) 
          .where("users.name like ?", "%#{search_query}%") 
     end 

    @found_ids = ar_query.pluck(:id) 

    ... 

    end 

end 

Khi phương pháp pluck được gọi, tôi có được điều này:

ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'users.name' in 'where clause': SELECT id FROM `published_posts` WHERE (users.name like '%Andrew%') ORDER BY published_posts.created_at DESC 

tôi có thể nhận được kết quả tôi đang tìm kiếm với

@found_ids = ar_query.select(:id).map{|r| r.id} 

nhưng tôi muốn sử dụng pluck vì dường như đó là cách dọn sạch hơn. Tôi không thể hiểu tại sao nó không hoạt động. Ý tưởng nào?

Trả lời

10

Bạn cần và phải làm joins thay vì includes tại đây.

Hai chức năng khá giống nhau ngoại trừ dữ liệu từ joins không được trả lại trong kết quả truy vấn trong khi dữ liệu trong một includes là.

Về mặt đó, includespluck là loại phản đối. Một người nói để trả lại cho tôi tất cả dữ liệu bạn có thể có, trong khi người kia nói rằng chỉ cho tôi một chút.

Vì bạn chỉ muốn một lượng nhỏ dữ liệu, bạn muốn thực hiện joins. (Kì lạ thay select mà cũng có vẻ hơi trái ngược vẫn hoạt động, nhưng bạn sẽ cần phải loại bỏ sự mơ hồ hơn id trong trường hợp này.)

Hãy thử nó ra trong giao diện điều khiển và bạn sẽ thấy rằng includes gây ra một truy vấn mà trông loại như thế này: SELECT "posts"."id" as t0_ro, "posts"."text" as t0_r1, "users"."id" as t1_r0, "users"."name" as t1_r1 ... Khi bạn tack vào một tuyên bố pluck tất cả những cột tx_ry điên biến mất và được thay thế bằng bất cứ điều gì bạn chỉ định.

Tôi hy vọng điều đó sẽ hữu ích, nhưng nếu không thì RailsCast này có thể. Nó được giải thích quanh mốc 5 phút.

http://railscasts.com/episodes/181-include-vs-joins

9

Nếu bạn đến đây bằng cách tìm kiếm "đường ray nhổ cột mơ hồ", bạn có thể muốn biết bạn chỉ có thể thay thế query.pluck(:id) với:

query.pluck("table_name.id") 
+0

Yessss! Tôi không biết tại sao điều này không có trong tài liệu? Ít nhất tôi không thấy nó. – FireDragon

0

truy vấn của bạn sẽ không hoạt động vì nó là bằng văn bản, ngay cả khi không có cuộc gọi nhổ.

Lý do là, mệnh đề WHERE của bạn bao gồm SQL theo nghĩa đen tham chiếu bảng người dùng mà Rails không nhận thấy và quyết định sử dụng nhiều truy vấn và tham gia vào bộ nhớ (.preload()) thay vì tham gia vào cấp cơ sở dữ liệu (.eager_load()):

SELECT * from published_posts WHERE users.name like "pattern" ORDER BY published_posts.created_at DESC 
SELECT * from posts WHERE id IN (a_list_of_all_post_ids_in_publised_posts_returned_above) 
SELECT * from users WHERE id IN (a_list_of_all_user_ids_in_posts_returned_above) 

Đầu tiên trong số 3 truy vấn không thành công và đó là lỗi bạn gặp phải.

Để buộc Rails sử dụng JOIN ở đây, bạn nên sử dụng rõ ràng .eager_load() thay vì .includes() hoặc thêm mệnh đề .references().

Ngoài ra, những gì @Geoff trả lời là viết tắt, bạn không thực sự cần phải .bao gồm() ở đây, mà là một .joins().

Các vấn đề liên quan