2012-04-01 9 views
5

Tôi đang cố gắng phân trang truy vấn ActiveRecord bị xáo trộn. Cú pháp để thực hiện điều này bằng cách sử dụng đá quý Kaminari là:Phân trang truy vấn ActiveRecord bị xáo trộn

@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20) 

Vấn đề với điều này là User.all được tái xáo trộn trên mỗi yêu cầu pagination, khiến hồ sơ trùng lặp được gọi. Có cách nào để ngăn chặn loại trùng lặp này không?

+1

Gọi 'User.all' có thể khiến máy chủ của bạn chậm lại đáng kể. Ngay cả khi bạn chỉ có 100 người dùng, bạn sẽ phải trả chi phí không cần thiết để đưa tất cả người dùng vào không gian bộ nhớ ruby ​​trong mọi yêu cầu. –

Trả lời

5

Bạn cần phải vượt qua hạt giống cho rand giữa các truy vấn

params[:seed] ||= Random.new_seed 
srand params[:seed].to_i 
@users = Kaminari.paginate_array(User.all.shuffle).page(params[:page]).per(20) 

Và theo quan điểm thêm params [: hạt giống] cho tất cả các liên kết Kaminari để trang

+0

cảm ơn bạn đã dẫn đầu! nếu có thể, bạn có thể giải thích cách thức hoạt động của nó không? Tôi không theo dõi hoàn toàn, vẫn không chắc chắn làm thế nào để thực hiện câu trả lời này. – neon

+0

Bạn có thể đọc tài liệu API về cách thức hoạt động của hạt giống http://ruby-doc.org/core-1.9.2/Random.html – MikDiet

+0

Tôi đã tìm ra, nhưng hiện tại mảng đang xuất hiện theo thứ tự xáo trộn giống nhau - nghĩa là ngay cả sau người dùng đăng xuất và đăng nhập lại, mảng vẫn giữ nguyên, ban đầu xáo trộn trật tự thay vì bị xáo trộn. Lạ thật. – neon

3

Như KandadaBoggu chỉ ra ở trên, lấy tất cả các User hồ sơ từ cơ sở dữ liệu là không hiệu quả khi bạn chỉ cần 20. Tôi sẽ đề nghị sử dụng MySQL's RAND() function để thực hiện ngẫu nhiên trước khi bạn trở về từ cơ sở dữ liệu. Bạn vẫn có thể chuyển giá trị hạt giống đến RAND() để đảm bảo việc xáo trộn chỉ xảy ra một lần mỗi phiên.

Ví dụ:

class User < ActiveRecord::Base 
    def self.randomized(seed = nil) 
    seed = seed.to_i rescue 0 
    order("RAND(#{seed})") 
    end 
end 

class UsersController < ApplicationController 
    before_filter :set_random_seed 

    def index 
    @users = User.randomized(session[:seed]).page(params[:page]).per(20) 
    end 

private 

    def set_random_seed 
    session[:seed] ||= Random.new_seed 
    end 
end 

Tôi không có một cài đặt MySQL để kiểm tra chống lại, nhưng điều này nên thực hiện tốt hơn so với mã ban đầu của bạn.

0

Bạn cũng có thể làm điều này:

class UsersController < ApplicationController 
    USERS_SEED = 1000 # Or any another not-so-big number 

    def set_random_seed 
    session[:seed] ||= Random.rand(USERS_SEED) 
    end 
end 

Random.new_seed sẽ tạo ra hầu như cùng một kết quả nếu dữ liệu của bạn không phải là lớn.