diff --git a/Gemfile b/Gemfile index 43ab3d5..2f263d7 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ ruby "3.1.1" gem "rails", "~> 7.0.2", ">= 7.0.2.2" gem "pg", "~> 1.1" gem "puma", "~> 5.0" +gem "jbuilder" gem "bootsnap", require: false @@ -13,5 +14,4 @@ group :development, :test do gem "rspec-rails", "~> 5.1" gem "factory_bot_rails", "~> 6.2" - gem "shoulda-matchers", "~> 5.1" end diff --git a/Gemfile.lock b/Gemfile.lock index dadd9d3..489d888 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -90,6 +90,9 @@ GEM io-wait (0.2.1) irb (1.4.1) reline (>= 0.3.0) + jbuilder (2.11.5) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) loofah (2.14.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -190,6 +193,7 @@ DEPENDENCIES bootsnap debug factory_bot_rails (~> 6.2) + jbuilder pg (~> 1.1) puma (~> 5.0) rails (~> 7.0.2, >= 7.0.2.2) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..2a7816c --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,53 @@ +class UsersController < ApplicationController + before_action :set_user, only: %i[ show update destroy ] + + # GET /users + # GET /users.json + def index + @users = User.all + end + + # GET /users/1 + # GET /users/1.json + def show + end + + # POST /users + # POST /users.json + def create + @user = User.new(user_params) + + if @user.save + render :show, status: :created, location: @user + else + render json: @user.errors, status: :unprocessable_entity + end + end + + # PATCH/PUT /users/1 + # PATCH/PUT /users/1.json + def update + if @user.update(user_params) + render :show, status: :ok, location: @user + else + render json: @user.errors, status: :unprocessable_entity + end + end + + # DELETE /users/1 + # DELETE /users/1.json + def destroy + @user.destroy + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_user + @user = User.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def user_params + params.require(:user).permit(:username) + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..0ed9edc --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,10 @@ +class User < ApplicationRecord + validates :username, + presence: true, + uniqueness: true, + length: { maximum: 14 }, + allow_nil: false, + format: { + with: /\A[a-zA-Z0-9]+\z/, + } +end diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder new file mode 100644 index 0000000..c88f34b --- /dev/null +++ b/app/views/users/_user.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! user, :id, :username, :created_at, :updated_at +json.url user_url(user, format: :json) diff --git a/app/views/users/index.json.jbuilder b/app/views/users/index.json.jbuilder new file mode 100644 index 0000000..98788da --- /dev/null +++ b/app/views/users/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @users, partial: "users/user", as: :user diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder new file mode 100644 index 0000000..ff40bb9 --- /dev/null +++ b/app/views/users/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "users/user", user: @user diff --git a/config/routes.rb b/config/routes.rb index 262ffd5..9fe51af 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,5 @@ Rails.application.routes.draw do - # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html + resources :users, only: [:show] - # Defines the root path route ("/") - # root "articles#index" + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html end diff --git a/db/migrate/20220227172543_create_users.rb b/db/migrate/20220227172543_create_users.rb new file mode 100644 index 0000000..b81656f --- /dev/null +++ b/db/migrate/20220227172543_create_users.rb @@ -0,0 +1,9 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :username, null: false, limit: 14, index: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b783f98..e4d1bb4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,8 +10,15 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 0) do +ActiveRecord::Schema[7.0].define(version: 2022_02_27_172543) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "users", force: :cascade do |t| + t.string "username", limit: 14, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["username"], name: "index_users_on_username" + end + end diff --git a/db/seeds.rb b/db/seeds.rb index bc25fce..83e1657 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,7 +1,3 @@ -# This file should contain all the record creation needed to seed the database with its default values. -# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). -# -# Examples: -# -# movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) -# Character.create(name: "Luke", movie: movies.first) +User.find_or_create_by(username: 'xpto') +User.find_or_create_by(username: 'admin') +User.find_or_create_by(username: 'geonizeli') \ No newline at end of file diff --git a/spec/factories/users.rb b/spec/factories/users.rb new file mode 100644 index 0000000..99925c3 --- /dev/null +++ b/spec/factories/users.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :user do + username { "xpto" } + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb new file mode 100644 index 0000000..6650589 --- /dev/null +++ b/spec/models/user_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +RSpec.describe User, type: :model do + describe 'validations' do + describe 'username' do + it 'presence' do + user = build(:user, username: nil) + + expect(user).to_not be_valid + end + + it 'uniqueness' do + create(:user, username: 'xpto') + user = build(:user, username: 'xpto') + + expect(user).to_not be_valid + end + + it 'max length 14' do + with_15_caracters = build(:user, username: 'asdfghjklzxcvhn') + with_14_caracters = build(:user, username: 'asdfghjklzxcvh') + + expect(with_15_caracters).to_not be_valid + expect(with_14_caracters).to be_valid + end + + it 'format' do + with_invalid_format = build(:user, username: 'asdfghjklzxcvh!') + with_valid_format = build(:user, username: 'asdfghjklzxcvh') + + expect(with_invalid_format).to_not be_valid + expect(with_valid_format).to be_valid + end + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c0c0dcc..7a193e8 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -34,6 +34,8 @@ RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.include FactoryBot::Syntax::Methods + # 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. @@ -62,10 +64,3 @@ RSpec.configure do |config| # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") end - -Shoulda::Matchers.configure do |config| - config.integrate do |with| - with.test_framework :rspec - with.library :rails - end -end diff --git a/spec/requests/users_spec.rb b/spec/requests/users_spec.rb new file mode 100644 index 0000000..b53e693 --- /dev/null +++ b/spec/requests/users_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +RSpec.describe "/users", type: :request do + let(:valid_attributes) { + { + username: 'geonizeli' + } + } + + describe "GET /show" do + it "renders a successful response" do + user = User.create! valid_attributes + get user_url(user), as: :json + expect(response).to be_successful + end + end +end diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb new file mode 100644 index 0000000..2efa471 --- /dev/null +++ b/spec/routing/users_routing_spec.rb @@ -0,0 +1,9 @@ +require "rails_helper" + +RSpec.describe UsersController, type: :routing do + describe "routing" do + it "routes to #show" do + expect(get: "/users/1").to route_to("users#show", id: "1") + end + end +end