diff --git a/Gemfile b/Gemfile index 87234d9..12fdb72 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,7 @@ gem 'puma', '>= 5.0' # gem "kredis" # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] -gem "bcrypt", "~> 3.1.7" +gem 'bcrypt', '~> 3.1.7' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: %i[windows jruby] @@ -33,7 +33,7 @@ gem 'bootsnap', require: false # gem "image_processing", "~> 1.2" # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin Ajax possible -# gem "rack-cors" +gem 'rack-cors' # Use Faraday for making HTTP requests gem 'faraday' diff --git a/Gemfile.lock b/Gemfile.lock index 0cd85a3..3998d89 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -177,6 +177,8 @@ GEM nio4r (~> 2.0) racc (1.8.1) rack (3.1.7) + rack-cors (2.0.2) + rack (>= 2.0.0) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) @@ -278,6 +280,7 @@ DEPENDENCIES pg (~> 1.1) pry (~> 0.14.2) puma (>= 5.0) + rack-cors rails (~> 7.1.3, >= 7.1.3.4) rspec-rails (~> 6.1) shoulda-matchers (~> 6.4) diff --git a/app/controllers/api/v1/sessions_controller.rb b/app/controllers/api/v1/sessions_controller.rb new file mode 100644 index 0000000..f10f5c7 --- /dev/null +++ b/app/controllers/api/v1/sessions_controller.rb @@ -0,0 +1,11 @@ +class Api::V1::SessionsController < ApplicationController + def create + user = User.find_by(email: params[:email]) + if user && user.authenticate(params[:password]) + session[:user_id] = user.id + render json: UserSerializer.new(user) + else + render json: { errors: [{ message: 'Invalid email or password' }] }, status: :unauthorized + end + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4ac8823..257a571 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,3 @@ class ApplicationController < ActionController::API + include ActionController::Cookies end diff --git a/config/application.rb b/config/application.rb index 6a1b62c..fb28f56 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,17 +1,17 @@ -require_relative "boot" +require_relative 'boot' -require "rails" +require 'rails' # Pick the frameworks you want: -require "active_model/railtie" -require "active_job/railtie" -require "active_record/railtie" -require "active_storage/engine" -require "action_controller/railtie" -require "action_mailer/railtie" -require "action_mailbox/engine" -require "action_text/engine" -require "action_view/railtie" -require "action_cable/engine" +require 'active_model/railtie' +require 'active_job/railtie' +require 'active_record/railtie' +require 'active_storage/engine' +require 'action_controller/railtie' +require 'action_mailer/railtie' +require 'action_mailbox/engine' +require 'action_text/engine' +require 'action_view/railtie' +require 'action_cable/engine' # require "rails/test_unit/railtie" # Require the gems listed in Gemfile, including any gems @@ -26,7 +26,7 @@ class Application < Rails::Application # Please, add to the `ignore` list any other `lib` subdirectories that do # not contain `.rb` files, or that should not be reloaded or eager loaded. # Common ones are `templates`, `generators`, or `middleware`, for example. - config.autoload_lib(ignore: %w(assets tasks)) + config.autoload_lib(ignore: %w[assets tasks]) # Configuration for the application, engines, and railties goes here. # @@ -40,5 +40,6 @@ class Application < Rails::Application # Middleware like session, flash, cookies can be added back manually. # Skip views, helpers and assets when generating a new resource. config.api_only = true + config.middleware.use ActionDispatch::Session::CookieStore end end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb index 0c5dd99..b005b8a 100644 --- a/config/initializers/cors.rb +++ b/config/initializers/cors.rb @@ -5,12 +5,12 @@ # Read more: https://github.com/cyu/rack-cors -# Rails.application.config.middleware.insert_before 0, Rack::Cors do -# allow do -# origins "example.com" -# -# resource "*", -# headers: :any, -# methods: [:get, :post, :put, :patch, :delete, :options, :head] -# end -# end +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'http://localhost:3000' + + resource '*', + headers: :any, + methods: %i[get post put patch delete options head], credentials: true + end +end diff --git a/config/routes.rb b/config/routes.rb index 2d87fbd..c2175b0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,6 +8,7 @@ namespace :api do namespace :v1 do resources :users, only: %i[create] + resources :sessions, only: %i[create] end end end diff --git a/spec/requests/api/v1/user_request_spec.rb b/spec/requests/api/v1/user_request_spec.rb index c02b28f..5c47bfd 100644 --- a/spec/requests/api/v1/user_request_spec.rb +++ b/spec/requests/api/v1/user_request_spec.rb @@ -36,4 +36,20 @@ expect(error[:errors].first[:message]).to eq("Password confirmation doesn't match Password") end end + + describe 'POST /sessions' do + it 'logs in a existing user' do + user = User.create(email: 'test@test.com', password: 'password', password_confirmation: 'password') + + post '/api/v1/sessions', params: { email: user.email, password: user.password } + + expect(response).to have_http_status(:ok) + + expect(session[:user_id]).to eq(user.id) + + response_body = JSON.parse(response.body, symbolize_names: true) + + expect(response_body[:data][:attributes][:email]).to eq(user.email) + end + end end