Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Pouvoir mettre à jour ou supprimer une question #24

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ gem 'bootsnap', '>= 1.4.2', require: false

gem 'rack-cors'

# Security
gem 'jwt'
gem 'omniauth-google-oauth2'

gem 'jwt'
# Utils
gem 'acts_as_paranoid', '~> 0.6'
gem 'premailer-rails'

group :development, :test do
Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ GEM
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2)
acts_as_paranoid (0.6.3)
activerecord (>= 4.2, < 7.0)
activesupport (>= 4.2, < 7.0)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
ast (2.4.0)
Expand Down Expand Up @@ -269,6 +272,7 @@ PLATFORMS
x86-mswin32

DEPENDENCIES
acts_as_paranoid (~> 0.6)
bootsnap (>= 1.4.2)
byebug
dotenv-rails
Expand Down
14 changes: 13 additions & 1 deletion app/controllers/api/v1/questions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,22 @@ def create
render status: :created
end

def update
@question = Question.find(params[:id])
Question.transaction do
@question.update(question_params)
raise ActionController::BadRequest, 'Answers should be filled' if @question.answers.empty?
end
end

def destroy
@question = Question.find(params[:id]).destroy
end

private

def question_params
new_params = params.permit(:title, :description, :endingDate, answers: %i[title description])
new_params = params.permit(:title, :description, :endingDate, answers: %i[id title description _destroy])
new_params[:ending_date] = new_params.delete :endingDate if params[:endingDate]
new_params[:answers_attributes] = new_params.delete :answers if params[:answers]
new_params
Expand Down
4 changes: 3 additions & 1 deletion app/models/question.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# frozen_string_literal: true

class Question < ApplicationRecord
acts_as_paranoid

has_many :answers
accepts_nested_attributes_for :answers
accepts_nested_attributes_for :answers, allow_destroy: true

validates :title, :description, :ending_date, presence: true
end
3 changes: 3 additions & 0 deletions app/views/api/v1/questions/update.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

json.partial! 'api/v1/questions/question', question: @question
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace :api do
namespace :v1, defaults: { content_type: 'application/json', format: :json } do
resources :questions, only: %i[index show create] do
resources :questions, only: %i[index show create update destroy] do
member do
resources :votes, only: %i[index create]
put 'votes', to: 'votes#update'
Expand Down
8 changes: 8 additions & 0 deletions db/migrate/20200318000057_add_deleted_at_to_question.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

class AddDeletedAtToQuestion < ActiveRecord::Migration[6.0]
def change
add_column :questions, :deleted_at, :datetime
add_index :questions, :deleted_at
end
end
15 changes: 8 additions & 7 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
# This file is the source Rails uses to define your schema when running `rails
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2019_11_08_164222) do
ActiveRecord::Schema.define(version: 2020_03_18_000057) do

# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
enable_extension "unaccent"
enable_extension "uuid-ossp"

create_table "answers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
Expand All @@ -33,6 +32,8 @@
t.datetime "ending_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
t.index ["deleted_at"], name: "index_questions_on_deleted_at"
end

create_table "votes", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
Expand Down
129 changes: 129 additions & 0 deletions spec/requests/api/v1/questions_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,133 @@
expect(response).to have_http_status :bad_request
end
end

# TODO: Block to the question user/owner
describe 'PUT /v1/questions/:id' do
subject(:update_question) do
put "/api/v1/questions/#{question.id}", params: question_new_parameters, headers: headers_of_logged_in_user
end

context 'parameters are good' do
let!(:answer_to_update) { create :answer, title: 'Answer to update', question: question }
let!(:answer_to_ignore) { create :answer, title: 'Answer to ignore', question: question }
let!(:answer_to_delete) { create :answer, title: 'Answer to delete', question: question }

let(:question_new_parameters) do
{
title: 'Nom de league?',
description: 'Quel est le nom de la league?',
endingDate: '2019-11-28T15:59:42.344Z',
answers: [
{ id: answer_to_update.id, title: 'Updated answer', description: 'New Description' },
{ id: answer_to_delete.id, title: 'Delete this', _destroy: 'true' },
{ title: 'New answer', description: 'FRONT API MOBILE EXPERIENCE' }
]
}
end

it 'returns a ok HTTP status' do
update_question

expect(response).to have_http_status :ok
end

it 'returns the updated question' do
update_question

parsed_body = JSON.parse(response.body)
expect(parsed_body.except('id', 'answers')).to eq('title' => 'Nom de league?',
'description' => 'Quel est le nom de la league?',
'endingDate' => '2019-11-28T15:59:42.344Z')
end

it 'adds one answer but removes one answer' do
expect { update_question }.not_to change(Answer, :count)
end

it 'returns the updated answers (one created, one updated, one deleted)' do
update_question

parsed_body = JSON.parse(response.body)
expected_answers = parsed_body['answers'].map { |answer| answer.except('id', 'description') }
expect(expected_answers).to eq([
{ 'title' => 'Updated answer' },
{ 'title' => 'Answer to ignore' },
{ 'title' => 'New answer' }
])
end
end

context 'no answer is given' do
let!(:answer) { create :answer, question: question }

let(:question_new_parameters) do
{
title: 'Nom de league?',
answers: []
}
end

it 'returns an ok HTTP status' do
update_question

expect(response).to have_http_status :ok
end
end

context 'asking to delete the last answer' do
let!(:answer) { create :answer, title: 'Last answer', question: question }

let(:question_new_parameters) do
{
title: 'Nom de league?',
answers: [
{ id: answer.id, title: 'Do not delete this', _destroy: 'true' }
]
}
end

it 'does not delete the answer' do
expect { update_question }.not_to change(Answer, :count)
end

it 'does not delete the answer 2' do
update_question

expect(answer.reload.title).to eq 'Last answer'
end

it 'returns a bad request HTTP status' do
update_question

expect(response).to have_http_status :bad_request
end
end
end

# TODO: Block to the question user/owner
describe 'DELETE /v1/questions/:id' do
subject(:delete_question) { delete "/api/v1/questions/#{question.id}", headers: headers_of_logged_in_user }

let!(:question) { create :question }

before do
create :answer, question: question
create :answer, question: question
end

it 'deletes the question' do
expect { delete_question }.to change(Question, :count).by(-1)
end

xit 'deletes two answers' do
expect { delete_question }.to change(Answer, :count).by(-2)
end

it 'returns a no_content HTTP status' do
delete_question

expect(response).to have_http_status :no_content
end
end
end