[RUBY] Beginners can see the Devise code and understand the mechanism softly [registrations new]

Introduction

The Rails tutorial is finally over. When I put in Devise of gem, I was surprised that the implementation of 5 to 6 chapters in the Rails tutorial was completed in about 10 minutes.

I don't know why it was made ... And I want to write a test, but I don't know how to write it. So I said, "Let's read the official and source code", but I read it, but I don't understand it at all ... but I want to understand it little by little, so I will read it.

While reading, I will summarize what I have investigated.

** ・ I'm a beginner but want to know how Devise works **

I hope it helps such a person.

Devise's GitHub https://github.com/heartcombo/devise

Devise overview

At the very beginning of the GitHub README is an overview.

--Devise is a flexible authentication solution for Rails based on Warden. --Rack base. --A complete MVC solution based on the Rails engine. --You can sign in to multiple models at the same time. --Based on the concept of modularity. Use only what you really need.

The Warden that appears here is a gem for authentication, and it seems that it is pulling this within devise.

Also, it is composed of 10 modules, and it seems that you should use what you need while uncommenting it. It's a module or a function. There was a person who made a table in Qiita, so I will quote it below.

|function|Overview| |:-----------------|:----------------| |database_authenticatable |When signing in, the password is hashed and registered in the DB to verify the validity of the user. You can use POST request or HTTP Basic authentication as the authentication method.| |registerable |Sign up the user through the registration process. It also allows users to edit and delete their accounts.| |recoverable |Reset your password and notify it.| |rememberable |Generates / deletes a token to remember the user from the saved cookie.| |trackable |Record the number of sign-ins, sign-in time, and IP address.| |validatable |Provides email and password validation. You can also add your own defined validations.| |confirmable |We provide a common registration method, such as clicking the URL in the email to complete the main registration. It also verifies that your account has been authenticated during sign-in.| |lockable |If you fail to sign in a certain number of times, your account will be locked. You can unlock it by email or after a certain period of time.| |timeoutable |Destroy the session of the account that has not been active for a certain period of time.| |omniauthable |intridea/Supports omniauth. Use this if you want to add authentication such as Twitter or Facebook.| Source: [* Rails *] How to use devise (rails6 version) https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974e

Devise also creates helpers for use within controllers and views. Frequently used commands are preset.

The helper name is illustrated assuming that the device model is'User', If the device model is non-user, replacing "_user" with "_yourmodel (arbitrary model name)" will apply the same logic.

This is also quoted because there was a person who made it a table in Qiita.

|Method|Use| |:-----------------|:----------------| |before_action :authenticate_user!|Set to controller to allow access only to logged-in users| |user_signed_in?|Determine if the user is signed in| |current_user|Get the signed-in user| |user_session|Access user session information| Source: List of helper methods available in Rails devise https://qiita.com/tobita0000/items/866de191635e6d74e392

registrations --Sign up / Edit / Delete account

Since this registration is responsible for CRUD of the most basic account, it seems difficult to read the code of the functional part of the application without knowing this.

I will fill in the entire code within the range examined from the top, but it may be difficult to understand because it is divided into different parts. It might be a little easier to understand if you look at it while putting the source code next to it ...

frozen_string_literal

devise/app/controllers/devise/registrations_controller.rb


# frozen_string_literal: true

Although it is commented out, it seems to be a sentence prepared for the version upgrade of Ruby. Reference: Method design principles that I noticed with frozen_string_literal https://qiita.com/jkr_2255/items/300b5db8c1f04e1e2815

prepend_before_action

devise/app/controllers/devise/registrations_controller.rb


class Devise::RegistrationsController < DeviseController
  prepend_before_action :require_no_authentication, only: [:new, :create, :cancel]   
  prepend_before_action :authenticate_scope!, only: [:edit, :update, :destroy]
  prepend_before_action :set_minimum_password_length, only: [:new, :edit]

--It inherits DeviseController. Looking at the source code file, devise_controller.rb is inherited not only by this module but also by all ** modules. ** ** --prepend_before_action is a ** method that is executed before before_action **. The actions that can be accessed are restricted by the user's login status. --Reference: Rails documentation https://railsdoc.com/page/prepend_before_action

new action

devise/app/controllers/devise/registrations_controller.rb


 # GET /resource/sign_up
  def new
    build_resource
    yield resource if block_given?
    respond_with resource
  end

--This is the first part to log in. -- resource is already defined in devise_controller.

devise/app/controllers/devise_controller.rb


  def resource
    instance_variable_get(:"@#{resource_name}")
  end

  # Proxy to devise map name
  def resource_name
    devise_mapping.name 
  end

  alias :scope_name :resource_name

--ʻInstance_variable_getmethod gets and returns the value of an instance variable. It seems to be the same as the definition from@ user =. --Reference: Ruby 2.7.0 Reference Manual https://docs.ruby-lang.org/ja/latest/method/Object/i/instance_variable_get.html --There is a variable called # {resource_name}inresource, but it is defined in the lower part. --devise_mapping.name` This is also already defined in devise_controller, but if you look at the quoted article, there seems to be a hint in another part.

devise/app/controllers/devise_controller.rb


  def devise_mapping 
    @devise_mapping ||= request.env["devise.mapping"]
  end

If you pay attention to> name and connect the code, if the authentication model is User, you can see @singular =: users.to_s.tr ('/','_'). Singularize.to_sym. singularize is a method that converts the plural to the singular, and finally @singular =: user and the alias of singular is name, so you can get: user with mapping.name. Then: user is passed to the argument of define_methods and authenticate_user! Is completed.

Source: Learn Rails with Devise Code Reading https://qiita.com/irisAsh/items/513b8b58f54421b9a1a0

To put it simply, since you can get : user with mapping.name, is it set to resource_name?

--There is a build_resource at the bottom of the registrations_controller. It seems to mean creating a new session.

devise/app/controllers/devise/registrations_controller.rb


 def build_resource(hash = {}) #build_resource(hash = {})Definition of
    self.resource = resource_class.new_with_session(hash, session)
  end

--Let's go back to the top of the original registrations_controller. build plays a role similar to new. The statement build_resource creates a session with the user's instance variables retrieved from the database. --block_given? Returns true if the block was passed when executing the method, false if it was not passed. --What is a block?

You can evaluate a block from within that method by calling a method with a piece of code (called a block) enclosed in> do ... end or {...}. Use the yield expression to define your own method with blocks. Source: Ruby 2.7.0 Reference Manual https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html#block

--In this case, the resource block is defined as yield and the authenticity is confirmed byblock_given?. It looks like we need to know more about yield. --Reference: What is yield @variable if block_given? https://kossy-web-engineer.hatenablog.com/entry/2020/01/19/094958- --Reference: [Introduction to Ruby] Summary of how to use yield https://www.sejuku.net/blog/20478

--I think that respond_with resource is called in relation to this area,

devise/app/controllers/devise_controller.rb


  def respond_with_navigational(*args, &block)
    respond_with(*args) do |format|
      format.any(*navigational_formats, &block)
    end
  end

devise/app/controllers/devise_controller.rb


  def navigational_formats
    @navigational_formats ||= Devise.navigational_formats.select { |format|Mime::EXTENSION_LOOKUP[format.to_s] }
  end

I'm not sure, so I'd like to study and make corrections.

It's so complicated Gem ... It's been a great learning experience because it's packed with just a few lines of code. I could only write new actions, but in the end I want to keep a record of reading just each action of registrations_controller ...!

Thank you for your relationship.

Recommended Posts

Beginners can see the Devise code and understand the mechanism softly [registrations new]
Understand the Singleton pattern by comparing Java and JavaScript code
Understand the Iterator pattern by comparing Java and JavaScript code