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
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
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
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}in
resource, 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.