[RUBY] Build a bulletin board API with authentication authorization in Rails 6 # 11 User model test and validation added

Building a bulletin board API with authentication authorization with Rails 6 # 10 devise_token_auth introduction

Preparing for the test

Implement validation and testing for user. It's no longer test-first, but since devise is special, I wanted to implement it to the point where it works, so the order is out of order.

First, prepare the files required for the test. The user model was generated with devise_token_auth, so there are no rspec and factoryBot files. Generate with the following command.

$ rails g rspec:model user
      create  spec/models/user_spec.rb
      invoke  factory_bot
      create    spec/factories/users.rb

Create the factory first.

spec/factories/users.rb


# frozen_string_literal: true

FactoryBot.define do
  factory :user do
    provider { "email" }
    sequence(:email) { |n| "test#{n}@example.com" }
    uid { email }
    password { "password" }
    remember_created_at { nil }
    name { "MyString" }
    tokens { nil }
  end
end

What happened to the columns in the user table? Then, you can check the output result by looking at db / schema.rb.

There are three things to note in the factory file. sequence(:email) { |n| "test#{n}@example.com" } uid { email } password { "password" } These are three.

sequence(:email) { |n| "test#{n}@example.com" } A serial number is entered in n of this process. The first record is [email protected], the second record is [email protected],….

The reason for doing this is that the email column is uniquely restricted and cannot be registered if it is the same character string. For example, if this is a constant ʻemail {"[email protected]"} , create_list (: user, 10) `will result in two or more corresponding email addresses and moss.

uid { email } It's just a simple uid with an email variable. The behavior of devise is uid = email if the provider is email.

password { "password" } The encrypted_password is on the DB column, but the hashed string is stored there. The column name does not match schema.rb because you need to enter a value for password when setting the password.

User model test

I want to run a test similar to post, so copy spec / models / post_spec.rb. Replace Post with ʻUser, subjectwithname, and body with ʻemail.

spec/models/user_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe User, type: :model do
  describe "name" do
    context "When blank" do
      let(:user) do
        build(:user, name: "")
      end
      it "Become invalid" do
        expect(user).not_to be_valid
      end
    end
    context "by maxlength" do
      context "For 30 characters" do
        let(:user) do
          build(:user, name: "Ah" * 30)
        end
        it "Become valid" do
          expect(user).to be_valid
        end
      end
      context "For 31 characters" do
        let(:user) do
          build(:user, name: "Ah" * 31)
        end
        it "Become invalid" do
          expect(user).not_to be_valid
        end
      end
    end
  end

  describe "email" do
    context "When blank" do
      let(:user) do
        build(:user, email: "")
      end
      it "Become invalid" do
        expect(user).not_to be_valid
      end
    end
    context "by maxlength" do
      context "For 100 characters" do
        let(:user) do
          build(:user, email: "@example.com".rjust(100, "a"))
        end
        it "Become valid" do
          expect(user).to be_valid
        end
      end
      context "For 101 characters" do
        let(:user) do
          build(:user, email: "@example.com".rjust(101, "a"))
        end
        it "Become invalid" do
          expect(user).not_to be_valid
        end
      end
    end
    context "By email format" do
      context "If the string is correct" do
        let(:user) do
          build(:user, email: "[email protected]")
        end
        it "Become valid" do
          expect(user).to be_valid
        end
      end
      context "In case of incorrect string" do
        let(:user) do
          build(:user, email: "test@example")
        end
        it "Become invalid" do
          expect(user).not_to be_valid
        end
      end
    end
  end
end

The following parts are not copied from post but replaced independently.

build(:user, email: "@example.com".rjust(100, "a"))
build(:user, email: "@example.com".rjust(101, "a"))

rjust is a method that fills the string with the specified characters so that it is right-justified. Try running it with rails c.

$ rails c
[1] pry(main)> "@example.com".rjust(100, "a")
=> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com"
[2] pry(main)> "@example.com".rjust(100, "a").length
=> 100

By doing this, you can generate dummy data that is perfect for 100 characters.

User model validation implementation

app/models/user.rb


 # frozen_string_literal: true

 #
 #User class
 #
 class User < ActiveRecord::Base
   # Include default devise modules. Others available are:
   # :confirmable, :lockable, :timeoutable and :omniauthable
   devise :database_authenticatable, :registerable,
          :rememberable, :validatable
   include DeviseTokenAuth::Concerns::User


+  validates :name, presence: true, length: { maximum: 30 }
+  validates :email, presence: true, length: { maximum: 100 }
end

Now it will pass the rspec test.

that? I haven't written the format validation of the email address, but why is it OK? If you feel it, it's sharp. Actually, the format of email is checked by : validatable of devise, so it is not necessary to specify the email format confirmation validation in the case of devise dependent model.

Write a request spec for auth

In this tutorial, I'll finish by writing a simple test that only requires registration and login.

$ rails g rspec:request v1/auth
      create  spec/requests/v1/auths_spec.rb
$ mv spec/requests/v1/auths_spec.rb spec/requests/v1/auth_spec.rb

Since auths is unpleasant, rename it to auth. Basically, I will write auth_spec.rb while referring to spec / requests / v1 / posts_spec.rb.

spec/requests/v1/auth_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe "V1::Auth", type: :request do
  describe "POST /v1/auth#create" do
    let(:user) do
      attributes_for(:user, email: "[email protected]", name: "signup test")
    end
    it "Normal response code is returned" do
      post v1_user_registration_url, params: user
      expect(response.status).to eq 200
    end
    it "One more case will be returned" do
      expect do
        post v1_user_registration_url, params: user
      end.to change { User.count }.by(1)
    end
    it "name is returned correctly" do
      post v1_user_registration_url, params: user
      json = JSON.parse(response.body)
      expect(json["data"]["name"]).to eq("signup test")
    end
    it "Errors are returned when the parameter is invalid" do
      post v1_user_registration_url, params: {}
      json = JSON.parse(response.body)
      expect(json.key?("errors")).to be true
    end
  end

  describe "POST /v1/auth/sign_in#create" do
    let(:user) do
      create(:user, email: "[email protected]", name: "signin test")
      { email: "[email protected]", password: "password" }
    end
    it "Normal response code is returned" do
      post v1_user_session_url, params: user, as: :json
      expect(response.status).to eq 200
    end
    it "name is returned correctly" do
      post v1_user_session_url, params: user
      json = JSON.parse(response.body)
      expect(json["data"]["name"]).to eq("signin test")
    end
    it "Errors are returned when the parameter is invalid" do
      post v1_user_session_url, params: {}
      json = JSON.parse(response.body)
      expect(json.key?("errors")).to be true
    end
  end
end

After writing so far, if rubocop and rspec pass normally, commit.

Continued

Building a bulletin board API with authentication authorization in Rails 6 # 12 Association of user and post [To the serial table of contents]

Recommended Posts

Build a bulletin board API with authentication authorization in Rails 6 # 11 User model test and validation added
Build a bulletin board API with authentication authorization in Rails # 12 Association of user and post
Build a bulletin board API with authentication and authorization with Rails 6 # 1 Environment construction
Build a bulletin board API with authentication authorization in Rails # 13 Add authentication header
Building a bulletin board API with authentication authorization with Rails 6 Validation and test implementation of # 4 post
Build a bulletin board API with authentication and authorization with Rails # 18 ・ Implementation of final user controller
Build a bulletin board API with authentication authorization with Rails 6 # 3 RSpec, FactoryBot introduced and post model
Build a bulletin board API with authentication authorization in Rails 6 # 5 controller, routes implementation
Introduced # 10 devise_token_auth to build a bulletin board API with authentication authorization in Rails 6
Build a bulletin board API with authentication authorization with Rails 6 # 2 Introducing git and rubocop
Introducing # 15 pundit to build a bulletin board API with authentication authorization in Rails 6
Build a bulletin board API with authentication authorization in Rails # 17 Add administrator privileges
Build a bulletin board API with authentication authorization in Rails 6 # 14 seed Execution time display
# 16 policy setting to build bulletin board API with authentication authorization in Rails 6
# 8 seed implementation to build bulletin board API with authentication authorization in Rails 6
Introduced # 9 serializer to build bulletin board API with authentication authorization in Rails 6
# 6 show, create implementation to build bulletin board API with authentication authorization in Rails 6
# 7 update, destroy implementation to build bulletin board API with authentication authorization in Rails 6
How to build API with GraphQL and Rails
I tried to express the phone number (landline / mobile phone) with a regular expression in Rails and write validation and test
I implemented Rails API with TDD by RSpec. part2 -user authentication-
How to rename a model with foreign key constraints in Rails
I tried to make a group function (bulletin board) with Rails
Build a Windows application test environment with Selenium Grid, Appium, and Windows Application Driver
[Rails 6] Register and log in with Devise + SNS authentication (multiple links allowed)
Create a SPA with authentication function with Rails API mode + devise_token_auth + Vue.js 3 (Rails edition)
[Rails] Unit test code for User model
[Ruby on Rails] Model test with RSpec
How to store data simultaneously in a model associated with a nested form (Rails 6.0.0)