[RUBY] Construire une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 18 ・ Implémentation du contrôleur de l'utilisateur final

Création d'une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 17 Ajout de privilèges d'administrateur

C'est la fin de la sérialisation en 18 parties.

Cette fois, nous allons créer un contrôleur utilisateur. C'est une compilation du passé, nous vous recommandons donc de l'essayer sans regarder l'exemple de code.

spécification

Il est principalement destiné aux administrateurs pour gérer les utilisateurs et en tant que groupe de fonctions permettant aux utilisateurs de se mettre à jour et de se supprimer.

procédure

  1. Créez users_controller
  2. Créez user_policy
  3. Mise en œuvre du test user_policy
  4. Mise en œuvre de user_policy
  5. Mise en œuvre du test users_controller
  6. Implémentation de users_controller

Je vais poursuivre la procédure.

1. Créez users_controller

Exemple d'implémentation
C'est facile parce que vous venez d'appuyer sur la commande.
$ rails g controller v1/users

Voici un groupe de fichiers qui ont été légèrement modifiés pour que rubocop ne se fâche pas.

app/controllers/v1/users_controller.rb


# frozen_string_literal: true

module V1
  #
  #  users controller
  #
  class UsersController < ApplicationController
  end
end

spec/requests/v1/users_request_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe "V1::Users", type: :request do
end

2. Créez user_policy

Exemple d'implémentation

Appuyez sur la commande pour créer un fichier.

$ rails g pundit:policy user

Après avoir apporté des modifications mineures pour que rubocop ne se fâche pas, il est terminé pour le moment.

app/policies/user_policy.rb


# frozen_string_literal: true

#
#classe de stratégie utilisateur
#
class UserPolicy < ApplicationPolicy
  #
  # scope
  #
  class Scope < Scope
    def resolve
      scope.all
    end
  end
end

spec/policies/user_policy_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe UserPolicy, type: :policy do
  let(:user) { User.new }

  subject { described_class }

  permissions ".scope" do
    pending "add some examples to (or delete) #{__FILE__}"
  end

  permissions :show? do
    pending "add some examples to (or delete) #{__FILE__}"
  end

  permissions :create? do
    pending "add some examples to (or delete) #{__FILE__}"
  end

  permissions :update? do
    pending "add some examples to (or delete) #{__FILE__}"
  end

  permissions :destroy? do
    pending "add some examples to (or delete) #{__FILE__}"
  end
end

3. Mise en œuvre du test user_policy

Exemple d'implémentation

Examen des spécifications.

  • #index Seuls les administrateurs peuvent afficher
  • #show Uniquement disponible pour vous-même ou l'administrateur
  • #create Seuls les administrateurs peuvent créer
  • #update Seuls vous ou votre administrateur pouvez mettre à jour
  • #destroy Seul l'administrateur peut supprimer

Il semble que l'index, #create, #destroy peut être partagé et #show, #update peut être partagé.

Voici la mise en œuvre dans cet esprit.

spec/policies/user_policy_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe UserPolicy, type: :policy do
  let(:user) { create(:user) }
  let(:another_user) { create(:user) }
  let(:admin_user) { create(:user, :admin) }

  subject { described_class }

  permissions :index?, :create?, :destroy? do
    it "Non autorisé lorsqu'il n'est pas connecté" do
      expect(subject).not_to permit(nil, user)
    end
    it "Non autorisé lorsque vous êtes connecté en tant qu'utilisateur non administrateur" do
      expect(subject).not_to permit(user, user)
    end
    it "Autorisé lorsque vous êtes connecté en tant qu'utilisateur administrateur" do
      expect(subject).to permit(admin_user, user)
    end
  end

  permissions :show?, :update? do
    it "Non autorisé lorsqu'il n'est pas connecté" do
      expect(subject).not_to permit(nil, user)
    end
    it "Non autorisé lors de la connexion mais avec un autre utilisateur" do
      expect(subject).not_to permit(user, another_user)
    end
    it "Autorisé lorsque vous êtes connecté en tant qu'utilisateur administrateur" do
      expect(subject).to permit(admin_user, user)
    end
    it "Autorisé une fois connecté et le même utilisateur" do
      expect(subject).to permit(user, user)
    end
  end
end

Le fait est qu'un autre utilisateur appelé ʻanother_user` est défini. Maintenant, nous n'avons pas défini de politique à ce stade, alors assurez-vous que certains tests sont de la mousse.

4. Mise en œuvre de user_policy

Exemple d'implémentation

app/policies/user_policy.rb


# frozen_string_literal: true

#
#classe de stratégie utilisateur
#
class UserPolicy < ApplicationPolicy
  def index?
    admin?
  end

  def show?
    me? || admin?
  end

  def create?
    admin?
  end

  def update?
    me? || admin?
  end

  def destroy?
    admin?
  end

  private

  def me?
    @record == @user
  end

  #
  # scope
  #
  class Scope < Scope
    def resolve
      scope.all
    end
  end
end

Le but est de définir une méthode privée appelée «me?» Dans user_policy.rb.

Le mien? Dans application_policy.rb comparé @ record.user == @ user avec ʻuser de @ record. Cependant, cette fois, nous vérifierons si «@ record» et «@ user» correspondent, donc la grammaire anglaise sera «me?» Au lieu de «mine?». De plus, il semble que seul users_controller puisse être comparé à ʻuser lui-même pour le moment, donc je l'ai proposé à user_policy au lieu de application_policy.

Le test devrait avoir réussi sans aucune mention spéciale. </ div> </ détails>

5. Mise en œuvre du test users_controller

Exemple d'implémentation

spec/requests/v1/users_request_spec.rb


# frozen_string_literal: true

require "rails_helper"

RSpec.describe "V1::Users", type: :request do
  before do
    @user = create(:user, name: "test utilisateur")
    @authorized_headers = authorized_user_headers @user
    admin = create(:user, :admin)
    @authorized_admin_headers = authorized_user_headers admin
  end
  describe "GET /v1/users#index" do
    before do
      create_list(:user, 3)
    end
    it "Le code de réponse normal est renvoyé" do
      get v1_users_url, headers: @authorized_admin_headers
      expect(response.status).to eq 200
    end
    it "Le numéro est renvoyé correctement" do
      get v1_users_url, headers: @authorized_admin_headers
      json = JSON.parse(response.body)
      expect(json["users"].length).to eq(3 + 2) #Comprend 2 pour les en-têtes
    end
    it "Les réponses sont renvoyées dans l'ordre décroissant de l'identifiant" do
      get v1_users_url, headers: @authorized_admin_headers
      json = JSON.parse(response.body)
      first_id = json["users"][0]["id"]
      expect(json["users"][1]["id"]).to eq(first_id - 1)
      expect(json["users"][2]["id"]).to eq(first_id - 2)
      expect(json["users"][3]["id"]).to eq(first_id - 3)
      expect(json["users"][4]["id"]).to eq(first_id - 4)
    end
  end

  describe "GET /v1/users#show" do
    it "Le code de réponse normal est renvoyé" do
      get v1_user_url({ id: @user.id }), headers: @authorized_headers
      expect(response.status).to eq 200
    end
    it "le nom est renvoyé correctement" do
      get v1_user_url({ id: @user.id }), headers: @authorized_headers
      json = JSON.parse(response.body)
      expect(json["user"]["name"]).to eq("test utilisateur")
    end
    it "La réponse 404 est renvoyée lorsque l'ID n'existe pas" do
      last_user = User.last
      get v1_user_url({ id: last_user.id + 1 }), headers: @authorized_headers
      expect(response.status).to eq 404
    end
  end

  describe "POST /v1/users#create" do
    let(:new_user) do
      attributes_for(:user, name: "create_test de nom", email: "[email protected]", admin: true)
    end
    it "Le code de réponse normal est renvoyé" do
      post v1_users_url, params: new_user, headers: @authorized_admin_headers
      expect(response.status).to eq 200
    end
    it "Un autre cas sera retourné" do
      expect do
        post v1_users_url, params: new_user, headers: @authorized_admin_headers
      end.to change { User.count }.by(1)
    end
    it "name, email,l'administrateur revient correctement" do
      post v1_users_url, params: new_user, headers: @authorized_admin_headers
      json = JSON.parse(response.body)
      expect(json["user"]["name"]).to eq("create_test de nom")
      expect(json["user"]["email"]).to eq("[email protected]")
      expect(json["user"]["admin"]).to be true
    end
    it "Des erreurs sont renvoyées lorsque le paramètre n'est pas valide" do
      post v1_users_url, params: {}, headers: @authorized_admin_headers
      json = JSON.parse(response.body)
      expect(json.key?("errors")).to be true
    end
  end

  describe "PUT /v1/users#update" do
    let(:update_param) do
      update_param = attributes_for(:user, name: "update_test de nom", email: "[email protected]", admin: true)
      update_param[:id] = @user.id
      update_param
    end
    it "Le code de réponse normal est renvoyé" do
      put v1_user_url({ id: update_param[:id] }), params: update_param, headers: @authorized_headers
      expect(response.status).to eq 200
    end
    it "name, email,l'administrateur revient correctement" do
      put v1_user_url({ id: update_param[:id] }), params: update_param, headers: @authorized_headers
      json = JSON.parse(response.body)
      expect(json["user"]["name"]).to eq("update_test de nom")
      expect(json["user"]["email"]).to eq("[email protected]")
      expect(json["user"]["admin"]).to be false #C'est un problème si l'autorité d'administration peut être réécrite, alors laissez-le comme faux
    end
    it "Des erreurs sont renvoyées lorsque le paramètre n'est pas valide" do
      put v1_user_url({ id: update_param[:id] }), params: { name: "" }, headers: @authorized_headers
      json = JSON.parse(response.body)
      expect(json.key?("errors")).to be true
    end
    it "La réponse 404 est renvoyée lorsque l'ID n'existe pas" do
      last_user = User.last
      put v1_user_url({ id: last_user.id + 1 }), params: update_param, headers: @authorized_admin_headers
      expect(response.status).to eq 404
    end
  end

  describe "DELETE /v1/users#destroy" do
    it "Le code de réponse normal est renvoyé" do
      delete v1_user_url({ id: @user.id }), headers: @authorized_admin_headers
      expect(response.status).to eq 200
    end
    it "Un de moins et revient" do
      expect do
        delete v1_user_url({ id: @user.id }), headers: @authorized_admin_headers
      end.to change { User.count }.by(-1)
    end
    it "La réponse 404 est renvoyée lorsque l'ID n'existe pas" do
      last_user = User.last
      delete v1_user_url({ id: last_user.id + 1 }), headers: @authorized_admin_headers
      expect(response.status).to eq 404
    end
  end
end

Il y a des considérations différentes de celles de la poste.

  • Puisque create (: user) est fait lors de la création de l'en-tête, écrivez le test en tenant compte de ces deux cas.
  • De même, lors de la vérification de l'identifiant qui n'existe pas, obtenez last_user et +1
  • Puisqu'il y a un problème si le drapeau admin est librement réécrit, le drapeau admin est reflété par create mais pas par update.

J'intègre autour.

De plus, comme il y a un jugement administratif dans la réponse, il est nécessaire de modifier le sérialiseur.

app/serializers/user_serializer.rb


 # user serializer
 #
 class UserSerializer < ActiveModel::Serializer
-  attributes :id, :name, :email
+  attributes :id, :name, :email, :admin
 end

Maintenant tu es prêt. Ensuite, nous entrerons dans l'implémentation du contrôleur. </ div> </ détails>

6. Implémentation de users_controller

Exemple d'implémentation

Modifiez les routes pour pouvoir accéder au contrôleur.

config/routes.rb


 Rails.application.routes.draw do
   namespace "v1" do
     resources :posts
+    resources :users
     mount_devise_token_auth_for "User", at: "auth"
   end

Vient ensuite le contrôleur. Cela peut être presque détourné de la poste.

app/controllers/v1/users_controller.rb


# frozen_string_literal: true

module V1
  #
  #  users controller
  #
  class UsersController < ApplicationController
    before_action :set_user, only: %i[show update destroy]

    def index
      users = User.order(created_at: :desc).limit(20)
      authorize users
      render json: users
    end

    def show
      authorize @user
      render json: @user
    end

    def create
      user = User.new(user_create_params)
      user[:provider] = :email
      authorize user
      if user.save
        render json: user
      else
        render json: { errors: user.errors }
      end
    end

    def update
      authorize @user
      if @user.update(user_params)
        render json: @user
      else
        render json: { errors: @user.errors }
      end
    end

    def destroy
      authorize @user
      @user.destroy
      render json: @user
    end

    private

    def set_user
      @user = User.find(params[:id])
    end

    def user_create_params
      #Autoriser la définition des privilèges d'administrateur uniquement lors de la création
      params.permit(:name, :email, :admin, :password)
    end

    def user_params
      params.permit(:name, :email, :password)
    end
  end
end

Comme je l'ai écrit dans la section test, l'administrateur ne l'autorise que lors de la création. </ div> </ détails>

c'est tout. Merci d'avoir visité notre site Web 18 fois.

Sur cette base, veuillez développer les fonctions telles que la fonction de commentaire et la connexion sociale.

table des matières

[Vers la table de sérialisation]

Recommended Posts