Fix random proposals order in the same session
Using `setseed` and ordering by `RAND()` doesn't always return the same
results because, although the generated random numbers will always be
the same, PostgreSQL doesn't guarantee the order of the rows it will
apply those random numbers to, similar to the way it doesn't guarantee
an order when the `ORDER BY` clause isn't specified.
Using something like `reorder("legislation_proposals.id % #{seed}")`,
like we do in budget investments, is certainly more elegant but it makes
the test checking two users get different results fail sometimes, so
that approach might need some adjustments in order to make the results
more random.
This commit is contained in:
@@ -103,7 +103,12 @@ class Legislation::ProcessesController < Legislation::BaseController
|
|||||||
@proposals = @proposals.search(params[:search]) if params[:search].present?
|
@proposals = @proposals.search(params[:search]) if params[:search].present?
|
||||||
|
|
||||||
@current_filter = "winners" if params[:filter].blank? && @proposals.winners.any?
|
@current_filter = "winners" if params[:filter].blank? && @proposals.winners.any?
|
||||||
@proposals = @proposals.send(@current_filter).page(params[:page])
|
|
||||||
|
if @current_filter == "random"
|
||||||
|
@proposals = @proposals.send(@current_filter, session[:random_seed]).page(params[:page])
|
||||||
|
else
|
||||||
|
@proposals = @proposals.send(@current_filter).page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
if @process.proposals_phase.started? || (current_user && current_user.administrator?)
|
if @process.proposals_phase.started? || (current_user && current_user.administrator?)
|
||||||
legislation_proposal_votes(@proposals)
|
legislation_proposal_votes(@proposals)
|
||||||
@@ -125,12 +130,9 @@ class Legislation::ProcessesController < Legislation::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_random_seed
|
def set_random_seed
|
||||||
seed = (params[:random_seed] || session[:random_seed] || rand).to_f
|
seed = (params[:random_seed] || session[:random_seed] || rand(10_000_000)).to_i
|
||||||
seed = (-1..1).cover?(seed) ? seed : 1
|
|
||||||
|
|
||||||
session[:random_seed] = seed
|
session[:random_seed] = seed
|
||||||
params[:random_seed] = seed
|
params[:random_seed] = seed
|
||||||
|
|
||||||
::Legislation::Proposal.connection.execute "select setseed(#{seed})"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -48,13 +48,23 @@ class Legislation::Proposal < ActiveRecord::Base
|
|||||||
scope :sort_by_title, -> { reorder(title: :asc) }
|
scope :sort_by_title, -> { reorder(title: :asc) }
|
||||||
scope :sort_by_id, -> { reorder(id: :asc) }
|
scope :sort_by_id, -> { reorder(id: :asc) }
|
||||||
scope :sort_by_supports, -> { reorder(cached_votes_score: :desc) }
|
scope :sort_by_supports, -> { reorder(cached_votes_score: :desc) }
|
||||||
scope :sort_by_random, -> { reorder("RANDOM()") }
|
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
||||||
scope :selected, -> { where(selected: true) }
|
scope :selected, -> { where(selected: true) }
|
||||||
scope :random, -> { sort_by_random }
|
scope :random, -> (seed) { sort_by_random(seed) }
|
||||||
scope :winners, -> { selected.sort_by_confidence_score }
|
scope :winners, -> { selected.sort_by_confidence_score }
|
||||||
|
|
||||||
|
def self.sort_by_random(seed)
|
||||||
|
ids = pluck(:id).shuffle(random: Random.new(seed))
|
||||||
|
|
||||||
|
return all if ids.empty?
|
||||||
|
|
||||||
|
ids_with_order = ids.map.with_index { |id, order| "(#{id}, #{order})" }.join(", ")
|
||||||
|
|
||||||
|
joins("LEFT JOIN (VALUES #{ids_with_order}) AS ids(id, ordering) ON #{table_name}.id = ids.id")
|
||||||
|
.order("ids.ordering")
|
||||||
|
end
|
||||||
|
|
||||||
def to_param
|
def to_param
|
||||||
"#{id}-#{title}".parameterize
|
"#{id}-#{title}".parameterize
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user