Merge pull request #3321 from consul/backport-fix_random_order
Fix random proposals order in the same session
This commit is contained in:
@@ -4,6 +4,7 @@ module Budgets
|
|||||||
include FeatureFlags
|
include FeatureFlags
|
||||||
include CommentableActions
|
include CommentableActions
|
||||||
include FlagActions
|
include FlagActions
|
||||||
|
include RandomSeed
|
||||||
include ImageAttributes
|
include ImageAttributes
|
||||||
|
|
||||||
PER_PAGE = 10
|
PER_PAGE = 10
|
||||||
@@ -119,16 +120,6 @@ module Budgets
|
|||||||
@investment_votes = current_user ? current_user.budget_investment_votes(investments) : {}
|
@investment_votes = current_user ? current_user.budget_investment_votes(investments) : {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_random_seed
|
|
||||||
if params[:order] == 'random' || params[:order].blank?
|
|
||||||
seed = params[:random_seed] || session[:random_seed] || rand
|
|
||||||
params[:random_seed] = seed
|
|
||||||
session[:random_seed] = params[:random_seed]
|
|
||||||
else
|
|
||||||
params[:random_seed] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def investment_params
|
def investment_params
|
||||||
params.require(:budget_investment)
|
params.require(:budget_investment)
|
||||||
.permit(:title, :description, :heading_id, :tag_list,
|
.permit(:title, :description, :heading_id, :tag_list,
|
||||||
@@ -170,7 +161,7 @@ module Budgets
|
|||||||
def investments
|
def investments
|
||||||
if @current_order == 'random'
|
if @current_order == 'random'
|
||||||
@budget.investments.apply_filters_and_search(@budget, params, @current_filter)
|
@budget.investments.apply_filters_and_search(@budget, params, @current_filter)
|
||||||
.send("sort_by_#{@current_order}", params[:random_seed])
|
.sort_by_random(session[:random_seed])
|
||||||
else
|
else
|
||||||
@budget.investments.apply_filters_and_search(@budget, params, @current_filter)
|
@budget.investments.apply_filters_and_search(@budget, params, @current_filter)
|
||||||
.send("sort_by_#{@current_order}")
|
.send("sort_by_#{@current_order}")
|
||||||
|
|||||||
10
app/controllers/concerns/random_seed.rb
Normal file
10
app/controllers/concerns/random_seed.rb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module RandomSeed
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def set_random_seed
|
||||||
|
seed = (params[:random_seed] || session[:random_seed] || rand(10_000_000)).to_i
|
||||||
|
|
||||||
|
session[:random_seed] = seed
|
||||||
|
params[:random_seed] = seed
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
class Legislation::ProcessesController < Legislation::BaseController
|
class Legislation::ProcessesController < Legislation::BaseController
|
||||||
|
include RandomSeed
|
||||||
|
|
||||||
has_filters %w[open past], only: :index
|
has_filters %w[open past], only: :index
|
||||||
has_filters %w[random winners], only: :proposals
|
has_filters %w[random winners], only: :proposals
|
||||||
|
|
||||||
@@ -103,7 +105,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.sort_by_random(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)
|
||||||
@@ -123,14 +130,4 @@ class Legislation::ProcessesController < Legislation::BaseController
|
|||||||
return if member_method?
|
return if member_method?
|
||||||
@process = ::Legislation::Process.find(params[:process_id])
|
@process = ::Legislation::Process.find(params[:process_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_random_seed
|
|
||||||
seed = (params[:random_seed] || session[:random_seed] || rand).to_f
|
|
||||||
seed = (-1..1).cover?(seed) ? seed : 1
|
|
||||||
|
|
||||||
session[:random_seed] = seed
|
|
||||||
params[:random_seed] = seed
|
|
||||||
|
|
||||||
::Legislation::Proposal.connection.execute "select setseed(#{seed})"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class Budget
|
|||||||
include Filterable
|
include Filterable
|
||||||
include Flaggable
|
include Flaggable
|
||||||
include Milestoneable
|
include Milestoneable
|
||||||
|
include Randomizable
|
||||||
|
|
||||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||||
belongs_to :heading
|
belongs_to :heading
|
||||||
@@ -55,7 +56,6 @@ class Budget
|
|||||||
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc, id: :desc) }
|
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc, id: :desc) }
|
||||||
scope :sort_by_ballots, -> { reorder(ballot_lines_count: :desc, id: :desc) }
|
scope :sort_by_ballots, -> { reorder(ballot_lines_count: :desc, id: :desc) }
|
||||||
scope :sort_by_price, -> { reorder(price: :desc, confidence_score: :desc, id: :desc) }
|
scope :sort_by_price, -> { reorder(price: :desc, confidence_score: :desc, id: :desc) }
|
||||||
scope :sort_by_random, ->(seed) { reorder("budget_investments.id % #{seed.to_f.nonzero? ? seed.to_f : 1}, budget_investments.id") }
|
|
||||||
|
|
||||||
scope :sort_by_id, -> { order("id DESC") }
|
scope :sort_by_id, -> { order("id DESC") }
|
||||||
scope :sort_by_title, -> { order("title ASC") }
|
scope :sort_by_title, -> { order("title ASC") }
|
||||||
|
|||||||
16
app/models/concerns/randomizable.rb
Normal file
16
app/models/concerns/randomizable.rb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module Randomizable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def sort_by_random(seed = rand(10_000_000))
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -12,6 +12,7 @@ class Debate < ActiveRecord::Base
|
|||||||
include Graphqlable
|
include Graphqlable
|
||||||
include Relationable
|
include Relationable
|
||||||
include Notifiable
|
include Notifiable
|
||||||
|
include Randomizable
|
||||||
|
|
||||||
acts_as_votable
|
acts_as_votable
|
||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
@@ -37,7 +38,6 @@ class Debate < ActiveRecord::Base
|
|||||||
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) }
|
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) }
|
||||||
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
|
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
|
||||||
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
||||||
scope :sort_by_random, -> { reorder("RANDOM()") }
|
|
||||||
scope :sort_by_relevance, -> { all }
|
scope :sort_by_relevance, -> { all }
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
scope :sort_by_recommendations, -> { order(cached_votes_total: :desc) }
|
scope :sort_by_recommendations, -> { order(cached_votes_total: :desc) }
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class Legislation::Proposal < ActiveRecord::Base
|
|||||||
include Documentable
|
include Documentable
|
||||||
include Notifiable
|
include Notifiable
|
||||||
include Imageable
|
include Imageable
|
||||||
|
include Randomizable
|
||||||
|
|
||||||
documentable max_documents_allowed: 3,
|
documentable max_documents_allowed: 3,
|
||||||
max_file_size: 3.megabytes,
|
max_file_size: 3.megabytes,
|
||||||
@@ -48,11 +49,9 @@ 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 :winners, -> { selected.sort_by_confidence_score }
|
scope :winners, -> { selected.sort_by_confidence_score }
|
||||||
|
|
||||||
def to_param
|
def to_param
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class Proposal < ActiveRecord::Base
|
|||||||
include EmbedVideosHelper
|
include EmbedVideosHelper
|
||||||
include Relationable
|
include Relationable
|
||||||
include Milestoneable
|
include Milestoneable
|
||||||
|
include Randomizable
|
||||||
|
|
||||||
acts_as_votable
|
acts_as_votable
|
||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
@@ -58,7 +59,6 @@ class Proposal < ActiveRecord::Base
|
|||||||
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) }
|
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) }
|
||||||
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
|
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
|
||||||
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
||||||
scope :sort_by_random, -> { reorder("RANDOM()") }
|
|
||||||
scope :sort_by_relevance, -> { all }
|
scope :sort_by_relevance, -> { all }
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
scope :sort_by_archival_date, -> { archived.sort_by_confidence_score }
|
scope :sort_by_archival_date, -> { archived.sort_by_confidence_score }
|
||||||
|
|||||||
@@ -685,16 +685,16 @@ feature 'Budget Investments' do
|
|||||||
expect(current_url).to include('page=1')
|
expect(current_url).to include('page=1')
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'Each user has a different and consistent random budget investment order when random_seed is disctint' do
|
scenario "Each user has a different and consistent random budget investment order" do
|
||||||
(Kaminari.config.default_per_page * 1.3).to_i.times { create(:budget_investment, heading: heading) }
|
(Kaminari.config.default_per_page * 1.3).to_i.times { create(:budget_investment, heading: heading) }
|
||||||
|
|
||||||
in_browser(:one) do
|
in_browser(:one) do
|
||||||
visit budget_investments_path(budget, heading: heading, random_seed: rand)
|
visit budget_investments_path(budget, heading: heading)
|
||||||
@first_user_investments_order = investments_order
|
@first_user_investments_order = investments_order
|
||||||
end
|
end
|
||||||
|
|
||||||
in_browser(:two) do
|
in_browser(:two) do
|
||||||
visit budget_investments_path(budget, heading: heading, random_seed: rand)
|
visit budget_investments_path(budget, heading: heading)
|
||||||
@second_user_investments_order = investments_order
|
@second_user_investments_order = investments_order
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user