diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ce9861547..51de9c678 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -15,6 +15,7 @@ //= require jquery-ui/widgets/datepicker //= require jquery-ui/i18n/datepicker-es //= require jquery-ui/widgets/autocomplete +//= require jquery-ui/widgets/sortable //= require jquery-fileupload/basic //= require foundation //= require turbolinks @@ -71,6 +72,7 @@ //= require leaflet //= require map //= require polls +//= require sortable var initialize_modules = function() { App.Comments.initialize(); @@ -110,6 +112,7 @@ var initialize_modules = function() { App.PollsAdmin.initialize(); App.Map.initialize(); App.Polls.initialize(); + App.Sortable.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/sortable.js.coffee b/app/assets/javascripts/sortable.js.coffee new file mode 100644 index 000000000..1af543f6a --- /dev/null +++ b/app/assets/javascripts/sortable.js.coffee @@ -0,0 +1,9 @@ +App.Sortable = + initialize: -> + $(".sortable").sortable + update: (event, ui) -> + new_order = $(this).sortable('toArray', {attribute: 'data-answer-id'}); + $.ajax + url: $('.sortable').data('js-url'), + data: {ordered_list: new_order}, + type: 'POST' diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index aff55c88c..3f93ffa6b 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -18,4 +18,5 @@ @import 'datepicker_overrides'; @import 'jquery-ui/autocomplete'; @import 'autocomplete_overrides'; +@import 'jquery-ui/sortable'; @import 'leaflet'; diff --git a/app/controllers/admin/poll/questions/answers_controller.rb b/app/controllers/admin/poll/questions/answers_controller.rb index 51c44dd94..bef176a22 100644 --- a/app/controllers/admin/poll/questions/answers_controller.rb +++ b/app/controllers/admin/poll/questions/answers_controller.rb @@ -39,6 +39,11 @@ class Admin::Poll::Questions::AnswersController < Admin::Poll::BaseController render 'admin/poll/questions/answers/documents' end + def order_answers + ::Poll::Question::Answer.order_answers(params[:ordered_list]) + render nothing: true + end + private def answer_params diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb index e6ef482a9..efcaf4635 100644 --- a/app/models/poll/question.rb +++ b/app/models/poll/question.rb @@ -10,7 +10,7 @@ class Poll::Question < ActiveRecord::Base has_many :comments, as: :commentable has_many :answers, class_name: 'Poll::Answer' - has_many :question_answers, class_name: 'Poll::Question::Answer' + has_many :question_answers, -> { order 'given_order asc' }, class_name: 'Poll::Question::Answer' has_many :partial_results belongs_to :proposal diff --git a/app/models/poll/question/answer.rb b/app/models/poll/question/answer.rb index b3324e57f..7514b85a4 100644 --- a/app/models/poll/question/answer.rb +++ b/app/models/poll/question/answer.rb @@ -1,5 +1,5 @@ class Poll::Question::Answer < ActiveRecord::Base - include Galleryable + include Galleryable include Documentable documentable max_documents_allowed: 3, max_file_size: 3.megabytes, @@ -10,8 +10,26 @@ class Poll::Question::Answer < ActiveRecord::Base has_many :videos, class_name: 'Poll::Question::Answer::Video' validates :title, presence: true + validates :given_order, presence: true, uniqueness: { scope: :question_id } + + before_validation :set_order, on: :create def description super.try :html_safe end + + def self.order_answers(ordered_array) + ordered_array.each_with_index do |answer_id, order| + find(answer_id).update_attribute(:given_order, (order + 1)) + end + end + + def set_order + next_position = self.class.last_position(question_id) + 1 + self.given_order = next_position + end + + def self.last_position(question_id) + where(question_id: question_id).maximum("given_order") || 0 + end end diff --git a/app/views/admin/poll/questions/show.html.erb b/app/views/admin/poll/questions/show.html.erb index 5baabeafe..205b707fb 100644 --- a/app/views/admin/poll/questions/show.html.erb +++ b/app/views/admin/poll/questions/show.html.erb @@ -47,30 +47,32 @@ <%= t("admin.questions.show.answers.videos") %> - <% @question.question_answers.each do |answer| %> - - <%= link_to answer.title, admin_answer_path(answer) %> - <%= answer.description %> - - (<%= answer.images.count %>) -
- <%= link_to t("admin.questions.show.answers.images_list"), - admin_answer_images_path(answer) %> - - - (<%= answer.documents.count rescue 0 %>) -
- <%= link_to t("admin.questions.show.answers.documents_list"), - admin_answer_documents_path(answer) %> - - - (<%= answer.videos.count %>) -
- <%= link_to t("admin.questions.show.answers.video_list"), - admin_answer_videos_path(answer) %> - - - <% end %> + + <% @question.question_answers.each do |answer| %> + + <%= link_to answer.title, admin_answer_path(answer) %> + <%= answer.description %> + + (<%= answer.images.count %>) +
+ <%= link_to t("admin.questions.show.answers.images_list"), + admin_answer_images_path(answer) %> + + + (<%= answer.documents.count rescue 0 %>) +
+ <%= link_to t("admin.questions.show.answers.documents_list"), + admin_answer_documents_path(answer) %> + + + (<%= answer.videos.count %>) +
+ <%= link_to t("admin.questions.show.answers.video_list"), + admin_answer_videos_path(answer) %> + + + <% end %> + <% if @question.video_url.present? %> diff --git a/config/routes.rb b/config/routes.rb index 83b5754d7..1fb74aa53 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -306,6 +306,7 @@ Rails.application.routes.draw do resources :videos, controller: 'questions/answers/videos' get :documents, to: 'questions/answers#documents' end + post '/answers/order_answers', to: 'questions/answers#order_answers' end end diff --git a/db/migrate/20171010143623_add_given_order_to_poll_question_answers.rb b/db/migrate/20171010143623_add_given_order_to_poll_question_answers.rb new file mode 100644 index 000000000..6161e55e4 --- /dev/null +++ b/db/migrate/20171010143623_add_given_order_to_poll_question_answers.rb @@ -0,0 +1,5 @@ +class AddGivenOrderToPollQuestionAnswers < ActiveRecord::Migration + def change + add_column :poll_question_answers, :given_order, :integer, default: 1 + end +end diff --git a/db/schema.rb b/db/schema.rb index 9adba12b1..b9a1524ab 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171006145053) do +ActiveRecord::Schema.define(version: 20171010143623) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -680,6 +680,7 @@ ActiveRecord::Schema.define(version: 20171006145053) do t.string "title" t.text "description" t.integer "question_id" + t.integer "given_order", default: 1 end add_index "poll_question_answers", ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree diff --git a/spec/factories.rb b/spec/factories.rb index a28471efc..69aa92c62 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -503,8 +503,8 @@ FactoryGirl.define do factory :poll_question_answer, class: 'Poll::Question::Answer' do association :question, factory: :poll_question - sequence(:title) { |n| "Question title #{n}" } - sequence(:description) { |n| "Question description #{n}" } + sequence(:title) { |n| "Answer title #{n}" } + sequence(:description) { |n| "Answer description #{n}" } end factory :poll_booth, class: 'Poll::Booth' do diff --git a/spec/features/admin/poll/questions/answers/answers_spec.rb b/spec/features/admin/poll/questions/answers/answers_spec.rb index 66918c4d8..48c2017f4 100644 --- a/spec/features/admin/poll/questions/answers/answers_spec.rb +++ b/spec/features/admin/poll/questions/answers/answers_spec.rb @@ -4,7 +4,7 @@ feature 'Answers' do background do admin = create(:administrator) - login_as (admin.user) + login_as admin.user end scenario 'Create' do @@ -24,9 +24,27 @@ feature 'Answers' do expect(page).to have_content(description) end + scenario 'Create second answer and place after the first one' do + question = create(:poll_question) + answer = create(:poll_question_answer, title: 'First', question: question, given_order: 1) + title = 'Second' + description = "Description" + + visit admin_question_path(question) + click_link 'Add answer' + + fill_in 'poll_question_answer_title', with: title + fill_in 'poll_question_answer_description', with: description + + click_button 'Save' + + expect(page.body.index('First')).to be < page.body.index('Second') + end + scenario 'Update' do question = create(:poll_question) - answer = create(:poll_question_answer, question: question, title: "Answer title") + answer = create(:poll_question_answer, question: question, title: "Answer title", given_order: 1) + answer2 = create(:poll_question_answer, question: question, title: "Another title", given_order: 2) visit admin_answer_path(answer) @@ -46,6 +64,8 @@ feature 'Answers' do expect(page).to have_content(new_title) expect(page).to_not have_content(old_title) + + expect(page.body.index(new_title)).to be < page.body.index(answer2.title) end end diff --git a/spec/features/polls/answers_spec.rb b/spec/features/polls/answers_spec.rb index f7dfd4d38..368597830 100644 --- a/spec/features/polls/answers_spec.rb +++ b/spec/features/polls/answers_spec.rb @@ -9,13 +9,15 @@ feature 'Answers' do scenario "Index" do question = create(:poll_question) - answer1 = create(:poll_question_answer, question: question) - answer2 = create(:poll_question_answer, question: question) + answer1 = create(:poll_question_answer, question: question, given_order: 1) + answer2 = create(:poll_question_answer, question: question, given_order: 2) visit admin_question_path(question) expect(page).to have_css(".poll_question_answer", count: 2) + expect(page.body.index(answer1.title)).to be < page.body.index(answer2.title) + within("#poll_question_answer_#{answer1.id}") do expect(page).to have_content answer1.title expect(page).to have_content answer1.description diff --git a/spec/features/polls/polls_spec.rb b/spec/features/polls/polls_spec.rb index 9fdb07255..fc21e1e5f 100644 --- a/spec/features/polls/polls_spec.rb +++ b/spec/features/polls/polls_spec.rb @@ -78,6 +78,30 @@ feature 'Polls' do expect(page).to have_content(proposal_question.title) end + scenario "Question answers appear in the given order" do + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, title: 'First', question: question, given_order: 1) + answer2 = create(:poll_question_answer, title: 'Second', question: question, given_order: 2) + + visit poll_path(poll) + + within("div#poll_question_#{question.id}") do + expect(page.body.index(answer1.title)).to be < page.body.index(answer2.title) + end + end + + scenario "More info answers appear in the given order" do + question = create(:poll_question, poll: poll) + answer1 = create(:poll_question_answer, title: 'First', question: question, given_order: 1) + answer2 = create(:poll_question_answer, title: 'Second', question: question, given_order: 2) + + visit poll_path(poll) + + within('div.poll-more-info-answers') do + expect(page.body.index(answer1.title)).to be < page.body.index(answer2.title) + end + end + scenario 'Non-logged in users' do question = create(:poll_question, poll: poll) answer1 = create(:poll_question_answer, question: question, title: 'Han Solo')