diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index a5aaf5c01..6e5b1df3d 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -32,6 +32,7 @@ var initialize_modules = function() { App.Tags.initialize(); App.Stats.initialize(); App.LocaleSwitcher.initialize(); + App.DebatesOrderSelector.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/debates_order_selector.js.coffee b/app/assets/javascripts/debates_order_selector.js.coffee new file mode 100644 index 000000000..94002f5ac --- /dev/null +++ b/app/assets/javascripts/debates_order_selector.js.coffee @@ -0,0 +1,17 @@ +App.DebatesOrderSelector = + + href_with_params: (query_params) -> + loc = window.location + + loc.protocol + "//" + loc.hostname + + (if loc.port then ':' + loc.port else '') + + loc.pathname + + loc.hash + + '?' + $.param(query_params) + + initialize: -> + $('.js-order-selector').on 'change', -> + query_params = window.getQueryParameters() + query_params['order'] = $(this).val() + window.location.assign(App.DebatesOrderSelector.href_with_params(query_params)) + diff --git a/app/controllers/debates_controller.rb b/app/controllers/debates_controller.rb index cf6d14f65..efa441d81 100644 --- a/app/controllers/debates_controller.rb +++ b/app/controllers/debates_controller.rb @@ -1,11 +1,12 @@ class DebatesController < ApplicationController + before_action :parse_order, only: :index before_action :authenticate_user!, except: [:index, :show] load_and_authorize_resource respond_to :html, :js def index - @debates = Debate.search(params).page(params[:page]).for_render + @debates = Debate.search(params).page(params[:page]).for_render.send("sort_by_#{@order}") set_debate_votes(@debates) end @@ -71,4 +72,9 @@ class DebatesController < ApplicationController @featured_tags = ActsAsTaggableOn::Tag.where(featured: true) end + def parse_order + @valid_orders = ['total_votes', 'created_at', 'likes'] + @order = @valid_orders.include?(params[:order]) ? params[:order] : 'created_at' + end + end diff --git a/app/helpers/debates_helper.rb b/app/helpers/debates_helper.rb new file mode 100644 index 000000000..52bb9c17c --- /dev/null +++ b/app/helpers/debates_helper.rb @@ -0,0 +1,12 @@ +module DebatesHelper + def available_options_for_order_selector(valid_orders, current_order) + options_for_select(available_order_filters_array(valid_orders), current_order) + end + + private + + def available_order_filters_array(orders) + orders.map { |f| [t("debates.index.order_#{f}"), f] } + end + +end diff --git a/app/models/debate.rb b/app/models/debate.rb index 15590fc60..779cca33a 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -28,6 +28,10 @@ class Debate < ActiveRecord::Base scope :archived, -> { where("archived_at IS NOT NULL AND hidden_at IS NULL") } scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") } scope :for_render, -> { includes(:tags) } + scope :sort_by_total_votes, -> { reorder(cached_votes_total: :desc) } + scope :sort_by_likes , -> { reorder(cached_votes_up: :desc) } + scope :sort_by_created_at, -> { reorder(created_at: :desc) } + # Ahoy setup visitable # Ahoy will automatically assign visit_id on create diff --git a/app/views/debates/_order_selector.erb b/app/views/debates/_order_selector.erb new file mode 100644 index 000000000..de18cfc45 --- /dev/null +++ b/app/views/debates/_order_selector.erb @@ -0,0 +1,5 @@ +
+ +
diff --git a/app/views/debates/index.html.erb b/app/views/debates/index.html.erb index 59d11f37c..13600160c 100644 --- a/app/views/debates/index.html.erb +++ b/app/views/debates/index.html.erb @@ -4,18 +4,7 @@

<%= t("debates.index.showing") %>

- - + <%= render 'order_selector' %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 049f15435..c1d872ea1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -33,9 +33,9 @@ en: index: create_debate: Create a debate showing: You are seeing debates - filter_news: the newest - filter_votes: the most voted - filter_rated: the best rated + order_created_at: the newest + order_total_votes: the most voted + order_likes: the best rated filter_topic: "You are seeing %{number} debates with the topic '%{topic}'" debate: debate: Debate diff --git a/config/locales/es.yml b/config/locales/es.yml index 58ae07441..c116b7899 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -33,9 +33,9 @@ es: index: create_debate: Crea un debate showing: "Estás viendo los debates" - filter_news: "más nuevos" - filter_votes: "más votados" - filter_rated: mejor valorados + order_created_at: "más nuevos" + order_total_votes: "más votados" + order_likes: mejor valorados filter_topic: "Estás viendo %{number} debates con el tema '%{topic}'" debate: debate: Debate diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 22b689308..82669770d 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -350,4 +350,60 @@ feature 'Debates' do expect(InappropiateFlag.flagged?(user, debate)).to_not be end + feature 'Debate index order filters', :js do + + before do + # TODO consider using debate title literally + @most_voted_debate = create(:debate) + @most_liked_debate = create(:debate) + @most_recent_debate = create(:debate) + create_list(:vote, 2, votable: @most_liked_debate) + create_list(:vote, 2, votable: @most_voted_debate, vote_flag: false) + create(:vote, votable: @most_voted_debate) + end + + scenario 'Default order is created_at' do + visit debates_path + + expect(page).to have_select('order-selector', selected: 'the newest') + expect(@most_recent_debate.title).to appear_before(@most_liked_debate.title) + end + + scenario 'Debates are ordered by most voted' do + visit debates_path + + select 'the most voted', from: 'order-selector' + expect(page).to have_select('order-selector', selected: 'the most voted') + + expect(find("#debates .debate", match: :first)).to have_content(@most_voted_debate.title) # Necessary to force capybara to wait for redirect + expect(current_url).to include('order=total_votes') + expect(@most_voted_debate.title).to appear_before(@most_liked_debate.title) + expect(@most_liked_debate.title).to appear_before(@most_recent_debate.title) + end + + scenario 'Debates are ordered by best rated' do + visit debates_path + + select 'the best rated', from: 'order-selector' + expect(find("#debates .debate", match: :first)).to have_content(@most_liked_debate.title) + + expect(current_url).to include('order=likes') + expect(@most_liked_debate.title).to appear_before(@most_voted_debate.title) + expect(@most_voted_debate.title).to appear_before(@most_recent_debate.title) + end + + scenario 'Debates are ordered by newest' do + visit debates_path + + select 'the most voted', from: 'order-selector' + expect(find("#debates .debate", match: :first)).to have_content(@most_voted_debate.title) + + select 'the newest', from: 'order-selector' + expect(find("#debates .debate", match: :first)).to have_content(@most_recent_debate.title) + + expect(current_url).to include('order=created_at') + expect(@most_recent_debate.title).to appear_before(@most_liked_debate.title) + expect(@most_liked_debate.title).to appear_before(@most_voted_debate.title) + end + end end diff --git a/spec/support/matchers/appear_before.rb b/spec/support/matchers/appear_before.rb new file mode 100644 index 000000000..bb1d65072 --- /dev/null +++ b/spec/support/matchers/appear_before.rb @@ -0,0 +1,6 @@ +RSpec::Matchers.define :appear_before do |later_content| + match do |earlier_content| + page.body.index(earlier_content) < page.body.index(later_content) + end +end +