简体   繁体   English

.order(“RANDOM()”)与will_paginate gem

[英].order(“RANDOM()”) with will_paginate gem

I am wondering if there is any way to still use the .order("RANDOM()") with will_paginate so that when a page loads and it orders the pages, all the post will stay the same on each page until the home page is reloaded. 我想知道是否有任何方法仍然使用.order("RANDOM()")will_paginate以便当页面加载并订购页面时,所有帖子将在每个页面上保持不变,直到主页为重新加载。

so to have all the posts on localhost:3000/posts?page=1 stay the same until localhost:3000(root_path) is visited again. 所以要在localhost:3000/posts?page=1上发布所有帖子localhost:3000/posts?page=1保持不变,直到再次访问localhost:3000(root_path)

Problem is it will paginate posts but it current re orders them for each page selected so you will often see posts on page 1 also on page 2. 问题是它会对帖子进行分页,但它会为每个选定的页面重新排序,因此您经常会在第2页上看到第1页上的帖子。

One way to do this is to set the random seed which your database is ordering by, such that it returns the same sequence of random numbers each time. 一种方法是设置数据库排序的随机种子 ,这样每次都返回相同的随机数序列。 You can store this seed in your users' session, and reset it only when you want to. 您可以将此种子存储在用户的会话中,并仅在需要时重置它。 However, there's a complication -- even though setting the random seed produces the same ordering of random numbers each time, there's no guarantee your database will execute it on your rows in the same order each time, unless you force it to do so like so: 然而,有一个复杂的问题 - 即使设置随机种子每次产生相同的随机数排序,也不能保证你的数据库每次都以相同的顺序在你的行上执行它,除非你强迫它这样做:

SELECT items.*
FROM (SELECT setseed(0.2)) t
   , (SELECT name, rank() OVER (ORDER BY name DESC)
      FROM foos ORDER BY name DESC) items
   JOIN generate_series(1, (SELECT COUNT(*) FROM foos))
     ON items.rank = generate_series
ORDER BY RANDOM()
LIMIT 10;

As you can tell, that's quite complicated, and it forces your database to materialize your entire table into memory. 正如您所知,这非常复杂,它会强制您的数据库将整个表格实现到内存中。 It'd work for smaller data sets, but if you've got a big data set, it's out of the question! 它适用于较小的数据集,但如果你有一个大数据集,那就不可能了!

Instead, I'd suggest you go with a solution more like tadman suggested above : generate a page of results, store the ids into session, and when you need to generate the next page, simply ignore anything you've already shown the user. 相反,我建议你使用更像上面提到的tadman的解决方案:生成一个结果页面,将id存储到会话中,当你需要生成下一页时,只需忽略你已经向用户显示的任何内容。 The code would look like: 代码看起来像:

class ThingsController < ApplicationController
  def index
    @page = params[:page].to_i
    session[:pages] ||= {}

    if ids = session[:pages][@page]
      # Grab the items we already showed, and ensure they show up in the same order.
      @things = Things.where(id: ids).sort_by { |thing| ids.index(thing.id) }
    else 
      # Generate a new page of things, filtering anything we've already shown.
      @things = Things.where(["id NOT IN (?)", shown_thing_ids])
                      .order("RANDOM()")
                      .limit(30) # your page size
      # Save the IDs into our session so the above case will work.
      session[:pages][@page] = @things.map(&:id)
    end
  end

  private
  def shown_thing_ids
    session[:pages].values.flatten
  end
end

This method uses the session to store which IDs were shown on each page, so you can guarantee the same set of items and ordering will be shown if the user goes back. 此方法使用会话来存储每个页面上显示的ID,因此您可以保证相同的项目集,并且如果用户返回,将显示排序。 For a new page, it will exclude any items already displayed. 对于新页面,它将排除已显示的任何项目。 You can reset the cache whenever you want with: 您可以随时重置缓存:

session.delete(:pages)

Hope that helps! 希望有所帮助! You could also use Redis or Memcache to store your page data, but the session is a good choice if you want the ordering to be random per-user. 您也可以使用Redis或Memcache来存储页面数据,但如果您希望按用户随机排序,则会话是一个不错的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM