From f35f30e2e8adbb010e7295bbd3b755baad398fea Mon Sep 17 00:00:00 2001 From: djeiky Date: Wed, 20 Sep 2017 16:04:52 +0300 Subject: [PATCH 1/3] add feature_helper, move database_cleaner settings --- spec/features/create_answer_spec.rb | 2 +- spec/features/delete_answer_spec.rb | 2 +- spec/features/delete_question_spec.rb | 2 +- spec/features/feature_helper.rb | 30 +++++++++++++++++++ spec/features/sign_in_user_spec.rb | 2 +- spec/features/user_register_spec.rb | 2 +- spec/features/user_sign_out_spec.rb | 2 +- .../view_questions_and_answers_spec.rb | 2 +- spec/features/view_questions_spec.rb | 2 +- spec/rails_helper.rb | 23 ++------------ 10 files changed, 40 insertions(+), 29 deletions(-) create mode 100644 spec/features/feature_helper.rb diff --git a/spec/features/create_answer_spec.rb b/spec/features/create_answer_spec.rb index 14d1d7c..f8eeafc 100644 --- a/spec/features/create_answer_spec.rb +++ b/spec/features/create_answer_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'User answer the question', %q{ In order to answer question diff --git a/spec/features/delete_answer_spec.rb b/spec/features/delete_answer_spec.rb index f02cf61..73a4650 100644 --- a/spec/features/delete_answer_spec.rb +++ b/spec/features/delete_answer_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'User delete answer', %q{ In order to delete answer diff --git a/spec/features/delete_question_spec.rb b/spec/features/delete_question_spec.rb index e7269b2..b15b613 100644 --- a/spec/features/delete_question_spec.rb +++ b/spec/features/delete_question_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'User delete question', %q{ In order to delete question diff --git a/spec/features/feature_helper.rb b/spec/features/feature_helper.rb new file mode 100644 index 0000000..20bfd1e --- /dev/null +++ b/spec/features/feature_helper.rb @@ -0,0 +1,30 @@ +require "rails_helper" + +RSpec.configure do |config| + + config.use_transactional_fixtures = false + + config.include FeatureHelper, type: :feature + + config.before(:suite) do + DatabaseCleaner.clean_with(:truncation) + end + + config.before(:each) do + DatabaseCleaner.strategy = :transaction + end + + config.before(:each, js: true) do + DatabaseCleaner.strategy = :truncation + end + + config.before(:each) do + DatabaseCleaner.start + end + + config.after(:each) do + DatabaseCleaner.clean + end + +end + diff --git a/spec/features/sign_in_user_spec.rb b/spec/features/sign_in_user_spec.rb index a0bf6db..d328fa1 100644 --- a/spec/features/sign_in_user_spec.rb +++ b/spec/features/sign_in_user_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'User sign in', %q{ In order to ask questions and give answers diff --git a/spec/features/user_register_spec.rb b/spec/features/user_register_spec.rb index ad8d04f..09814ac 100644 --- a/spec/features/user_register_spec.rb +++ b/spec/features/user_register_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'Register user', %q{ User can register diff --git a/spec/features/user_sign_out_spec.rb b/spec/features/user_sign_out_spec.rb index c6f49ad..f58d266 100644 --- a/spec/features/user_sign_out_spec.rb +++ b/spec/features/user_sign_out_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'User sign out', %q{ User can sign out diff --git a/spec/features/view_questions_and_answers_spec.rb b/spec/features/view_questions_and_answers_spec.rb index c0bdb7f..a60e258 100644 --- a/spec/features/view_questions_and_answers_spec.rb +++ b/spec/features/view_questions_and_answers_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature "User can view question and it's answers", %q{ In order to see question with answers diff --git a/spec/features/view_questions_spec.rb b/spec/features/view_questions_spec.rb index 0386c47..093e0bd 100644 --- a/spec/features/view_questions_spec.rb +++ b/spec/features/view_questions_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative 'feature_helper' feature 'Any user view list of questions', %q{ In order to find question diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 626c409..69df9b5 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -37,7 +37,7 @@ # If you're not using ActiveRecord, or you'd prefer not to run each of your # examples within a transaction, remove the following line or assign false # instead of true. - config.use_transactional_fixtures = false + config.use_transactional_fixtures = true # RSpec Rails can automatically mix in different behaviours to your tests # based on their file location, for example enabling you to call `get` and @@ -58,26 +58,7 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") - config.before(:suite) do - DatabaseCleaner.clean_with(:truncation) - end - - config.before(:each) do - DatabaseCleaner.strategy = :transaction - end - - config.before(:each, js: true) do - DatabaseCleaner.strategy = :truncation - end - - config.before(:each) do - DatabaseCleaner.start - end - - config.after(:each) do - DatabaseCleaner.clean - end -end + end Shoulda::Matchers.configure do |config| config.integrate do |with| From 0e3a0e25999bac2b1ebaf5adfa8b6f0d332a5b8b Mon Sep 17 00:00:00 2001 From: djeiky Date: Thu, 21 Sep 2017 17:49:47 +0300 Subject: [PATCH 2/3] only author can edit his questions and answers --- Gemfile | 2 +- Gemfile.lock | 14 ++---- app/assets/javascripts/answers.js.coffee | 9 ++++ app/assets/stylesheets/application.css.scss | 1 + app/controllers/answers_controller.rb | 13 +++-- app/controllers/questions_controller.rb | 15 ++++-- app/views/answers/_answer.html.haml | 15 ++++-- app/views/answers/create.js.erb | 2 + app/views/answers/destroy.js.erb | 4 ++ app/views/answers/update.js.erb | 5 ++ app/views/questions/_form.html.haml | 2 +- app/views/questions/edit.html.haml | 4 +- app/views/questions/index.html.haml | 2 + app/views/questions/show.html.haml | 4 +- spec/controllers/answers_controller_spec.rb | 47 ++++++++++++++++--- spec/controllers/questions_controller_spec.rb | 12 ++--- .../{ => answers}/create_answer_spec.rb | 4 +- .../{ => answers}/delete_answer_spec.rb | 6 +-- .../features/answers/user_edit_answer_spec.rb | 44 +++++++++++++++++ spec/features/feature_helper.rb | 2 + .../{ => questions}/create_question_spec.rb | 6 +-- .../{ => questions}/delete_question_spec.rb | 2 +- .../questions/user_edit_question_spec.rb | 44 +++++++++++++++++ .../view_questions_and_answers_spec.rb | 2 +- .../{ => questions}/view_questions_spec.rb | 2 +- 25 files changed, 214 insertions(+), 49 deletions(-) create mode 100644 app/assets/javascripts/answers.js.coffee create mode 100644 app/views/answers/destroy.js.erb create mode 100644 app/views/answers/update.js.erb rename spec/features/{ => answers}/create_answer_spec.rb (87%) rename spec/features/{ => answers}/delete_answer_spec.rb (80%) create mode 100644 spec/features/answers/user_edit_answer_spec.rb rename spec/features/{ => questions}/create_question_spec.rb (89%) rename spec/features/{ => questions}/delete_question_spec.rb (93%) create mode 100644 spec/features/questions/user_edit_question_spec.rb rename spec/features/{ => questions}/view_questions_and_answers_spec.rb (89%) rename spec/features/{ => questions}/view_questions_spec.rb (86%) diff --git a/Gemfile b/Gemfile index ce8a550..e55fd29 100644 --- a/Gemfile +++ b/Gemfile @@ -42,7 +42,7 @@ group :development, :test do gem 'rails-controller-testing' gem 'capybara' gem 'launchy' - gem 'selenium-webdriver', '~> 2.53.4' + gem 'capybara-webkit' gem 'geckodriver-helper' gem 'database_cleaner' end diff --git a/Gemfile.lock b/Gemfile.lock index 54dcb14..11ffafb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -60,8 +60,9 @@ GEM rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) - childprocess (0.7.1) - ffi (~> 1.0, >= 1.0.11) + capybara-webkit (1.1.0) + capybara (~> 2.0, >= 2.0.2) + json coffee-rails (4.2.2) coffee-script (>= 2.2.0) railties (>= 4.0.0) @@ -113,6 +114,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) + json (2.1.0) launchy (2.4.3) addressable (~> 2.3) listen (3.0.8) @@ -206,7 +208,6 @@ GEM ruby-progressbar (1.8.1) ruby_parser (3.9.0) sexp_processor (~> 4.1) - rubyzip (1.2.1) sass (3.5.0) sass-listen (~> 3.0.7) sass-listen (3.0.7) @@ -218,10 +219,6 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - selenium-webdriver (2.53.4) - childprocess (~> 0.5) - rubyzip (~> 1.0) - websocket (~> 1.0) sexp_processor (4.9.0) shoulda-matchers (3.1.2) activesupport (>= 4.0.0) @@ -256,7 +253,6 @@ GEM activemodel (>= 5.0) bindex (>= 0.4.0) railties (>= 5.0) - websocket (1.2.4) websocket-driver (0.6.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -271,6 +267,7 @@ DEPENDENCIES bootstrap-sass byebug capybara + capybara-webkit coffee-rails (~> 4.2) database_cleaner devise @@ -288,7 +285,6 @@ DEPENDENCIES rspec-rails rubocop sass-rails (~> 5.0) - selenium-webdriver (~> 2.53.4) shoulda-matchers spring spring-watcher-listen (~> 2.0.0) diff --git a/app/assets/javascripts/answers.js.coffee b/app/assets/javascripts/answers.js.coffee new file mode 100644 index 0000000..301d578 --- /dev/null +++ b/app/assets/javascripts/answers.js.coffee @@ -0,0 +1,9 @@ +editanswer = -> + $('.edit-answer-link').click (e) -> + e.preventDefault() + $(this).hide() + answer_id = $(this).data('answerId') + $('form#edit-answer-' + answer_id).show() + +$(document).ready(editanswer) +$(document).on('turbolinks:load', editanswer) diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index a54e74b..9c31704 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -1,3 +1,4 @@ @import "bootstrap-sprockets"; @import "bootstrap"; +.edit_answer {display: none;} diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index edd20aa..2ab55ed 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -1,7 +1,7 @@ class AnswersController < ApplicationController before_action :authenticate_user! - before_action :set_question, only: [:new, :create, :destroy] - before_action :set_answer, only: [:destroy] + before_action :set_question, only: [:new, :create, :destroy, :update] + before_action :set_answer, only: [:destroy, :update] def create @answer = @question.answers.new(answer_params) @@ -10,6 +10,14 @@ def create end + def update + if current_user.author_of?(@answer) + render "error" unless @answer.update(answer_params) + else + flash[:notice] = "You are not auther of the answer" + end + end + def destroy if current_user.author_of?(@answer) flash[:notice] = "Your answer successfully deleted." @@ -17,7 +25,6 @@ def destroy else flash[:notice] = "You are not author of the answer" end - redirect_to question_path(@question) end private diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index c05c1c4..f7c175b 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -25,13 +25,22 @@ def show end def edit + if current_user.author_of?(@question) + render :edit + else + redirect_to questions_path + end end def update - if @question.update(questions_params) - redirect_to question_path(@question) + if current_user.author_of?(@question) + if @question.update(questions_params) + redirect_to questions_path + else + render :edit + end else - render :edit + redirect_to questions_path end end diff --git a/app/views/answers/_answer.html.haml b/app/views/answers/_answer.html.haml index a294fde..6f9584f 100644 --- a/app/views/answers/_answer.html.haml +++ b/app/views/answers/_answer.html.haml @@ -1,7 +1,14 @@ - if answer.persisted? - .row + .row{id: "answer-body-#{answer.id}"} = answer.body - .row - - if current_user&.author_of?(answer) - = link_to 'Delete answer', question_answer_path(@question, answer), method: :delete + .row + - if current_user&.author_of?(answer) + %p + = link_to "Edit", '', class: "edit-answer-link", data: {answer_id: answer.id} + = form_for [@question, answer], remote: true, html: {id: "edit-answer-#{answer.id}"} do |f| + = f.label :body + = f.text_area :body + = f.submit "Save" + %p + = link_to 'Delete answer', question_answer_path(@question, answer), method: :delete, remote: true diff --git a/app/views/answers/create.js.erb b/app/views/answers/create.js.erb index 75a3c85..735ed23 100644 --- a/app/views/answers/create.js.erb +++ b/app/views/answers/create.js.erb @@ -1,2 +1,4 @@ +$("textarea#new_answer_body").val(""); $(".answers").append("<%= j render @answer%>"); + diff --git a/app/views/answers/destroy.js.erb b/app/views/answers/destroy.js.erb new file mode 100644 index 0000000..b2cfc60 --- /dev/null +++ b/app/views/answers/destroy.js.erb @@ -0,0 +1,4 @@ +$(".row#answer-body-<%= @answer.id%>").html(''); +$(".alert").html("Your answer successfully deleted.") + + diff --git a/app/views/answers/update.js.erb b/app/views/answers/update.js.erb new file mode 100644 index 0000000..31530c6 --- /dev/null +++ b/app/views/answers/update.js.erb @@ -0,0 +1,5 @@ +$('.row#answer-body-' + <%= @answer.id %>).html('<%= j @answer.body%>'); +$('form#edit-answer-' + <%= @answer.id %>).hide(); +$('.edit-answer-link[data-answer-id="<%= @answer.id %>"]').show(); + + diff --git a/app/views/questions/_form.html.haml b/app/views/questions/_form.html.haml index 5e37ca2..dec731f 100644 --- a/app/views/questions/_form.html.haml +++ b/app/views/questions/_form.html.haml @@ -13,4 +13,4 @@ .col-md-8 = f.text_area :body .row - = f.submit "Create" + = f.submit "Save" diff --git a/app/views/questions/edit.html.haml b/app/views/questions/edit.html.haml index d3f5a12..7b4ed2f 100644 --- a/app/views/questions/edit.html.haml +++ b/app/views/questions/edit.html.haml @@ -1 +1,3 @@ - += render "form" +%br += link_to "Назад", root_path diff --git a/app/views/questions/index.html.haml b/app/views/questions/index.html.haml index e068452..aa84ad1 100644 --- a/app/views/questions/index.html.haml +++ b/app/views/questions/index.html.haml @@ -4,6 +4,8 @@ - @questions.each do |question| .row %h2= link_to question.title, question_path(question) + - if current_user && current_user.author_of?(question) + %p= link_to "Edit",edit_question_path(question) .row %br %br diff --git a/app/views/questions/show.html.haml b/app/views/questions/show.html.haml index 963116e..8e459b5 100644 --- a/app/views/questions/show.html.haml +++ b/app/views/questions/show.html.haml @@ -5,7 +5,7 @@ = @question.body .row - if current_user&.author_of?(@question) - = link_to 'Delete question', question_path(@question), method: :delete + = link_to 'Delete question', question_path(@question), method: :delete, remote: true .row %h3Комментарии .row @@ -19,7 +19,7 @@ = render "shared/error_form", object: f.object .row = f.label :body - = f.text_field :body + = f.text_area :body, id: "new_answer_body" = f.submit "Create answer" .row = link_to "Назад", questions_path diff --git a/spec/controllers/answers_controller_spec.rb b/spec/controllers/answers_controller_spec.rb index 049a221..d49b478 100644 --- a/spec/controllers/answers_controller_spec.rb +++ b/spec/controllers/answers_controller_spec.rb @@ -3,7 +3,7 @@ RSpec.describe AnswersController, :type => :controller do sign_in_user let!(:question) { create(:question, user: @user) } - let!(:answer) {create( :answer, question: question)} + let!(:answer) {create( :answer, question: question, user: @user)} describe 'POST #create' do context 'valid answer' do @@ -36,23 +36,58 @@ end end + describe 'PATCH #update' do + + it 'assigns @answer to requested answer' do + patch :update, params: {id: answer, question_id: question, answer: attributes_for(:answer)}, format: :js + expect(assigns(:answer)).to eq answer + end + + it 'changes answer attributes' do + patch :update, params: {id: answer, question_id: question, answer: {body: "NewBody"}}, format: :js + answer.reload + expect(answer.body).to eq "NewBody" + + end + + it 'render template update' do + patch :update, params: {id: answer, question_id: question, answer: {body: "NewBody"}}, format: :js + expect(response).to render_template :update + end + + it 'render error template if errors exists' do + patch :update, params: {id: answer, question_id: question, answer: {body: ""}}, format: :js + expect(response).to render_template :error + end + + let!(:another_user) {create(:user)} + let(:another_answer) {create(:answer, question: question, user: another_user)} + it 'not change answer if user not author' do + patch :update, params: {id: another_answer, question_id: question, answer: {body: "NewBody"}}, format: :js + another_answer.reload + expect(another_answer.body).to eq "Answer body" + + end + + end + describe 'DELETE #destroy' do sign_in_user it "user tries to delete own answer" do answer = create(:answer, question: question, user: @user) - expect{delete :destroy, params:{ question_id: question, id: answer}}.to change(Answer, :count).by(-1) + expect{delete :destroy, params:{ question_id: question, id: answer}, format: :js}.to change(Answer, :count).by(-1) end it "user can't delete someone else question" do another_answer = create(:answer, question: question, user: create(:user)) - expect{delete :destroy, params: {question_id: question, id: another_answer}}.to_not change(Answer, :count) + expect{delete :destroy, params: {question_id: question, id: another_answer}, format: :js}.to_not change(Answer, :count) end - it "redirects to question show page" do - delete :destroy, params: {question_id: question, id: answer} - expect(response).to redirect_to question_path(question) + it "render destroy template" do + delete :destroy, params: {question_id: question, id: answer}, format: :js + expect(response).to render_template :destroy end end end diff --git a/spec/controllers/questions_controller_spec.rb b/spec/controllers/questions_controller_spec.rb index 440dc88..337195a 100644 --- a/spec/controllers/questions_controller_spec.rb +++ b/spec/controllers/questions_controller_spec.rb @@ -1,8 +1,9 @@ require 'rails_helper' RSpec.describe QuestionsController, :type => :controller do - let(:user) { create(:user) } - let(:question) { create(:question, user: user) } + + sign_in_user + let(:question) { create(:question, user: @user) } describe 'GET #index' do let(:questions) { create_list(:question, 2) } @@ -31,7 +32,6 @@ end describe 'GET #new' do - sign_in_user before {get :new} @@ -45,7 +45,6 @@ end describe 'GET #edit' do - sign_in_user before {get :edit, params: {id: question}} @@ -59,7 +58,6 @@ end describe 'POST #create' do - sign_in_user context 'valid attributes' do it 'saves question to database' do @@ -85,7 +83,6 @@ end describe 'PATCH #update' do - sign_in_user context 'valid attributes' do it 'assigns @question to requested question' do @@ -103,7 +100,7 @@ it 'redirects to updated question' do patch :update, params: {id: question, question: {title: "NewTitle", body: "NewBody"}} - expect(response). to redirect_to question + expect(response). to redirect_to questions_path end end @@ -126,7 +123,6 @@ end describe 'DELETE #destroy' do - sign_in_user before {question} diff --git a/spec/features/create_answer_spec.rb b/spec/features/answers/create_answer_spec.rb similarity index 87% rename from spec/features/create_answer_spec.rb rename to spec/features/answers/create_answer_spec.rb index f8eeafc..899b569 100644 --- a/spec/features/create_answer_spec.rb +++ b/spec/features/answers/create_answer_spec.rb @@ -1,4 +1,4 @@ -require_relative 'feature_helper' +require_relative '../feature_helper' feature 'User answer the question', %q{ In order to answer question @@ -13,7 +13,7 @@ visit question_path(question) - fill_in 'Body', with: "comment" + fill_in 'new_answer_body', with: "comment" click_on 'Create answer' within ".answers" do diff --git a/spec/features/delete_answer_spec.rb b/spec/features/answers/delete_answer_spec.rb similarity index 80% rename from spec/features/delete_answer_spec.rb rename to spec/features/answers/delete_answer_spec.rb index 73a4650..18e9a30 100644 --- a/spec/features/delete_answer_spec.rb +++ b/spec/features/answers/delete_answer_spec.rb @@ -1,4 +1,4 @@ -require_relative 'feature_helper' +require_relative '../feature_helper' feature 'User delete answer', %q{ In order to delete answer @@ -10,7 +10,7 @@ given!(:answer) {create(:answer, user: user, question: question)} given!(:another_question) {create(:question, user: user)} given!(:another_answer) {create(:answer, question: another_question, user: create(:user))} - scenario 'Authenticated user tries to delete own answer' do + scenario 'Authenticated user tries to delete own answer', js: true do sign_in user visit question_path question @@ -19,7 +19,7 @@ expect(page).to have_content 'Your answer successfully deleted.' expect(page).to_not have_content answer.body end - scenario 'Authenticated user tries to delete own answer' do + scenario 'Authenticated user tries to delete other user answer', js: true do sign_in user visit question_path another_question diff --git a/spec/features/answers/user_edit_answer_spec.rb b/spec/features/answers/user_edit_answer_spec.rb new file mode 100644 index 0000000..bec8540 --- /dev/null +++ b/spec/features/answers/user_edit_answer_spec.rb @@ -0,0 +1,44 @@ +require_relative '../feature_helper' + +feature "Users can edit answers", %q{ + In order to edit answer + Users have the oppotunity edit answers +} do + + given!(:user) { create(:user) } + given!(:question) {create(:question, user: user)} + given(:answer) {create(:answer, question: question, user: user)} + given!(:another_user) {create(:user)} + given(:another_answer) {create(:answer, question: question, user: another_user)} + + scenario "Unauthenticated user can't edit answers", js: true do + visit question_path(question) + + expect(page).to_not have_link "Edit" + end + + scenario "Authot of the answer can edit answer", js: true do + answer + sign_in user + visit question_path(question) + + within ".answers" do + click_on "Edit" + fill_in "Body", with: "answer has been edeted" + click_on "Save" + + expect(page).to_not have_content answer.body + expect(page).to have_content "answer has been edeted" + expect(page).to_not have_selector "textarea" + end + end + + scenario "Authenticated user can't edit answer of other user", js: true do + another_answer + sign_in user + visit question_path(question) + + expect(page).to_not have_selector ".edit-answer-link[data-answer-id=\"#{another_answer.id}\"]" + + end +end diff --git a/spec/features/feature_helper.rb b/spec/features/feature_helper.rb index 20bfd1e..a79ab6e 100644 --- a/spec/features/feature_helper.rb +++ b/spec/features/feature_helper.rb @@ -2,6 +2,8 @@ RSpec.configure do |config| + Capybara.javascript_driver = :webkit + config.use_transactional_fixtures = false config.include FeatureHelper, type: :feature diff --git a/spec/features/create_question_spec.rb b/spec/features/questions/create_question_spec.rb similarity index 89% rename from spec/features/create_question_spec.rb rename to spec/features/questions/create_question_spec.rb index eceaf4a..eca1de3 100644 --- a/spec/features/create_question_spec.rb +++ b/spec/features/questions/create_question_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require_relative '../feature_helper' feature 'Create questions', %q{ In order to get answers @@ -14,7 +14,7 @@ fill_in "Title", with: "NewTitle" fill_in "Body", with: "NewBody" - click_on "Create" + click_on "Save" expect(page).to have_content 'Your question successfully created.' expect(page).to have_content 'NewTitle' @@ -28,7 +28,7 @@ fill_in "Title", with: '' fill_in "Body", with: 'Question body' - click_on "Create" + click_on "Save" expect(page).to have_content "Title can't be blank" end diff --git a/spec/features/delete_question_spec.rb b/spec/features/questions/delete_question_spec.rb similarity index 93% rename from spec/features/delete_question_spec.rb rename to spec/features/questions/delete_question_spec.rb index b15b613..dc20719 100644 --- a/spec/features/delete_question_spec.rb +++ b/spec/features/questions/delete_question_spec.rb @@ -1,4 +1,4 @@ -require_relative 'feature_helper' +require_relative '../feature_helper' feature 'User delete question', %q{ In order to delete question diff --git a/spec/features/questions/user_edit_question_spec.rb b/spec/features/questions/user_edit_question_spec.rb new file mode 100644 index 0000000..1e390e2 --- /dev/null +++ b/spec/features/questions/user_edit_question_spec.rb @@ -0,0 +1,44 @@ +require_relative '../feature_helper' + +feature "Users can edit questions", %q{ + In order to edit answer + Users have the oppotunity edit answers +} do + + given!(:user) { create(:user) } + given(:question) {create(:question, user: user)} + given!(:another_user) {create(:user)} + given(:another_question) {create(:question, user: another_user)} + + scenario "Unauthenticated user can't edit questions" do + question + visit questions_path + + expect(page).to_not have_link "Edit" + end + + scenario "Authot of the question can edit answer", js: true do + question + sign_in user + visit questions_path + + click_on "Edit" + fill_in "Title", with: "edited title" + fill_in "Body", with: "edited body" + click_on "Save" + + expect(page).to_not have_content question.title + expect(page).to have_content "edited title" + expect(page).to_not have_selector "textarea" + + end + + scenario "Authenticated user can't edit answer of other user" do + another_question + sign_in user + visit edit_question_path(another_question) + + expect(current_path).to eq questions_path + + end +end diff --git a/spec/features/view_questions_and_answers_spec.rb b/spec/features/questions/view_questions_and_answers_spec.rb similarity index 89% rename from spec/features/view_questions_and_answers_spec.rb rename to spec/features/questions/view_questions_and_answers_spec.rb index a60e258..80a265e 100644 --- a/spec/features/view_questions_and_answers_spec.rb +++ b/spec/features/questions/view_questions_and_answers_spec.rb @@ -1,4 +1,4 @@ -require_relative 'feature_helper' +require_relative '../feature_helper' feature "User can view question and it's answers", %q{ In order to see question with answers diff --git a/spec/features/view_questions_spec.rb b/spec/features/questions/view_questions_spec.rb similarity index 86% rename from spec/features/view_questions_spec.rb rename to spec/features/questions/view_questions_spec.rb index 093e0bd..39520f1 100644 --- a/spec/features/view_questions_spec.rb +++ b/spec/features/questions/view_questions_spec.rb @@ -1,4 +1,4 @@ -require_relative 'feature_helper' +require_relative '../feature_helper' feature 'Any user view list of questions', %q{ In order to find question From 4f16c40522cb1a3979358e61e8b3dc0db37aac10 Mon Sep 17 00:00:00 2001 From: djeiky Date: Fri, 29 Sep 2017 17:07:55 +0300 Subject: [PATCH 3/3] finish part 7 --- app/controllers/answers_controller.rb | 13 ++++++- app/models/answer.rb | 7 ++++ app/models/question.rb | 2 +- app/views/answers/_answer.html.haml | 4 +- app/views/answers/best.js.erb | 5 +++ bin/bundle | 0 bin/rails | 0 bin/rake | 0 bin/setup | 0 bin/spring | 0 bin/update | 0 config/routes.rb | 4 +- .../20170929121314_add_best_to_answers.rb | 5 +++ db/schema.rb | 3 +- spec/controllers/questions_controller_spec.rb | 8 ++++ spec/factories/answers.rb | 2 + spec/features/answers/best_answer_spec.rb | 37 +++++++++++++++++++ spec/models/answer_spec.rb | 18 +++++++++ spec/models/question_spec.rb | 12 ++++++ 19 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 app/views/answers/best.js.erb mode change 100755 => 100644 bin/bundle mode change 100755 => 100644 bin/rails mode change 100755 => 100644 bin/rake mode change 100755 => 100644 bin/setup mode change 100755 => 100644 bin/spring mode change 100755 => 100644 bin/update create mode 100644 db/migrate/20170929121314_add_best_to_answers.rb create mode 100644 spec/features/answers/best_answer_spec.rb diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 2ab55ed..4b28ceb 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -1,7 +1,7 @@ class AnswersController < ApplicationController before_action :authenticate_user! - before_action :set_question, only: [:new, :create, :destroy, :update] - before_action :set_answer, only: [:destroy, :update] + before_action :set_question, only: [:new, :create, :destroy, :update, :best] + before_action :set_answer, only: [:destroy, :update, :best] def create @answer = @question.answers.new(answer_params) @@ -27,6 +27,15 @@ def destroy end end + def best + if current_user.author_of?(@question) + @answer.set_best + else + render[:notice] = "You are not author of the question" + end + + end + private def set_question diff --git a/app/models/answer.rb b/app/models/answer.rb index f9abcd0..e88b804 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -3,4 +3,11 @@ class Answer < ApplicationRecord belongs_to :user validates :body, presence: true + + def set_best + Answer.transaction do + self.question.answers.update_all(best: false) + self.update!(best: true) + end + end end diff --git a/app/models/question.rb b/app/models/question.rb index 4f12bcd..b6402eb 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -1,5 +1,5 @@ class Question < ApplicationRecord - has_many :answers, dependent: :destroy + has_many :answers,-> { order(best: :desc) }, dependent: :destroy belongs_to :user validates :title, presence: true diff --git a/app/views/answers/_answer.html.haml b/app/views/answers/_answer.html.haml index 6f9584f..68a8eea 100644 --- a/app/views/answers/_answer.html.haml +++ b/app/views/answers/_answer.html.haml @@ -1,7 +1,9 @@ - if answer.persisted? - .row{id: "answer-body-#{answer.id}"} + .row{id: "answer-body-#{answer.id}", class: ("best-answer" unless answer.best?)} = answer.body .row + - if current_user && current_user.author_of?(@question) && !answer.best? + = link_to "best", best_question_answer_path(@question, answer), remote: true, method: :put - if current_user&.author_of?(answer) %p = link_to "Edit", '', class: "edit-answer-link", data: {answer_id: answer.id} diff --git a/app/views/answers/best.js.erb b/app/views/answers/best.js.erb new file mode 100644 index 0000000..a3fd923 --- /dev/null +++ b/app/views/answers/best.js.erb @@ -0,0 +1,5 @@ +alert('Hello'); +$(".answers").html("<%= j render @question.answers%>"); +$(".alert").html("You chose best answer."); + + diff --git a/bin/bundle b/bin/bundle old mode 100755 new mode 100644 diff --git a/bin/rails b/bin/rails old mode 100755 new mode 100644 diff --git a/bin/rake b/bin/rake old mode 100755 new mode 100644 diff --git a/bin/setup b/bin/setup old mode 100755 new mode 100644 diff --git a/bin/spring b/bin/spring old mode 100755 new mode 100644 diff --git a/bin/update b/bin/update old mode 100755 new mode 100644 diff --git a/config/routes.rb b/config/routes.rb index 0bf2295..58fb233 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,6 +4,8 @@ root "questions#index" resources :questions do - resources :answers + resources :answers do + put :best, on: :member + end end end diff --git a/db/migrate/20170929121314_add_best_to_answers.rb b/db/migrate/20170929121314_add_best_to_answers.rb new file mode 100644 index 0000000..17a2559 --- /dev/null +++ b/db/migrate/20170929121314_add_best_to_answers.rb @@ -0,0 +1,5 @@ +class AddBestToAnswers < ActiveRecord::Migration[5.0] + def change + add_column :answers, :best, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 04ce00e..682a8cb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170713165150) do +ActiveRecord::Schema.define(version: 20170929121314) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -21,6 +21,7 @@ t.datetime "updated_at", null: false t.integer "question_id" t.integer "user_id" + t.boolean "best" t.index ["question_id"], name: "index_answers_on_question_id", using: :btree t.index ["user_id"], name: "index_answers_on_user_id", using: :btree end diff --git a/spec/controllers/questions_controller_spec.rb b/spec/controllers/questions_controller_spec.rb index 337195a..46eb7d8 100644 --- a/spec/controllers/questions_controller_spec.rb +++ b/spec/controllers/questions_controller_spec.rb @@ -103,6 +103,14 @@ expect(response). to redirect_to questions_path end + + + let!(:another_user) { create(:user) } + let!(:another_question) {create(:question, user: another_user)} + it 'non author tries to edit question' do + patch :update, params: {id: another_question, question: {title: "NewTitle", body: "NewBody"}} + expect(response).to redirect_to questions_path + end end context 'invalid attributes' do diff --git a/spec/factories/answers.rb b/spec/factories/answers.rb index 1387f1a..7b3332e 100644 --- a/spec/factories/answers.rb +++ b/spec/factories/answers.rb @@ -3,9 +3,11 @@ body "Answer body" question user + best false end factory :invalid_answer, class: "Answer" do body nil + best false end end diff --git a/spec/features/answers/best_answer_spec.rb b/spec/features/answers/best_answer_spec.rb new file mode 100644 index 0000000..85c75f4 --- /dev/null +++ b/spec/features/answers/best_answer_spec.rb @@ -0,0 +1,37 @@ +require_relative '../feature_helper' + +feature 'choose best answer', %q{ + In order to choose best answer + As author of the question + I want to be able choose an answer +} do + + describe "Author's question" do + given(:user) { create(:user) } + given(:question) {create(:question, user: user)} + given(:answers) {create_list(:answer, 3 , question: question)} + given(:another_user) {create(:user)} + given(:another_question) {create(:question, user: another_user)} + given(:another_answers) {create_list(:answer, 3, question: another_question)} + + scenario "Author tries to choose best answer", js: true do + sign_in user + answers + visit question_path(question) + + click_on "best", match: :first + + expect(page).to have_css ".best-answer" + end + + scenario "User tries to choose best answer for another user question" do + sign_in user + visit question_path(another_question) + + expect(page).to_not have_link "best" + end + + end + +end + diff --git a/spec/models/answer_spec.rb b/spec/models/answer_spec.rb index af76d8e..5f8e9e0 100644 --- a/spec/models/answer_spec.rb +++ b/spec/models/answer_spec.rb @@ -4,4 +4,22 @@ it {should validate_presence_of :body } it {should belong_to :question } it {should belong_to :user} + + let(:user) {create(:user)} + let(:question) {create(:question)} + let!(:answers) {create_list(:answer, 3, question: question, user: user)} + + it "should set first answer to best" do + question.answers.first.set_best + expect(question.answers.first.best).to be true + end + + it "should set second ansewr to best and first answer to false" do + first_answer = question.answers.first + second_answer = question.answers.second + second_answer.set_best + question.reload + expect(second_answer.best).to be true + expect(first_answer.best).to be false + end end diff --git a/spec/models/question_spec.rb b/spec/models/question_spec.rb index 5c70e76..399a8fd 100644 --- a/spec/models/question_spec.rb +++ b/spec/models/question_spec.rb @@ -5,4 +5,16 @@ it {should validate_presence_of :body } it {should have_many(:answers).dependent(:destroy) } it {should belong_to(:user)} + + let(:user) {create(:user) } + let(:question) {create(:question, user: user)} + let!(:answers) {create_list(:answer, 3, question: question, user: user)} + + it "Shoule have best answer first" do + question.answers.second.set_best + question.reload + + expect(question.answers.first.best).to be true + + end end