C'est le deuxième projet pour apprendre à écrire comme ruby en interprétant la définition de la méthode rails. Le thème cette fois est redirect_to
# File actionpack/lib/action_controller/metal/redirecting.rb, line 56
def redirect_to(options = {}, response_status = {})
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(request, options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
end
def redirect_to(options = {}, response_status = {})
Prend deux arguments. Dans les deux cas, un hachage vide est attribué si aucun argument n'est passé.
raise ActionControllerError.new("Cannot redirect to nil!") unless options
Génère une erreur lorsque les options sont vides. Au fait, ruby traite tout sauf false et nil comme true, donc un hachage vide {} ne provoquera pas d'erreur. Une erreur se produit lorsque l'utilisateur ose attribuer nil / false.
raise AbstractController::DoubleRenderError if response_body
Une erreur se produira si vous avez déjà reçu une réponse HTTP. Je ne sais pas comment response_body est affecté ici, mais il semble renvoyer une erreur lorsque plusieurs communications HTTP sont échangées en même temps.
self.status = _extract_redirect_to_status(options, response_status)
Une nouvelle méthode est également sortie cette fois.
#Fileactionpack/lib/action_controller/metal/redirecting.rb, line 117
def _extract_redirect_to_status(options, response_status)
if options.is_a?(Hash) && options.key?(:status)
Rack::Utils.status_code(options.delete(:status))
elsif response_status.key?(:status)
Rack::Utils.status_code(response_status[:status])
else
302
end
end
if options.is_a?(Hash) && options.key?(:status)
Un élément de la condition if is_a? Méthode est le type dans lequel le type du récepteur (ici "options") est écrit entre parenthèses. Une méthode qui renvoie true si elle correspond (ici "hash").
Les deux éléments key? de la condition if sont les clés dont les noms sont écrits entre parenthèses. Une méthode qui renvoie true si c'est le cas.
En d'autres termes, si l'argument passé à redirect_to est un hachage et a le statut de clé, le contenu de l'instruction if sera exécuté. Comme vous pouvez le voir dans le document Rails mentionné au début
redirect_to post_url(@post), status: :found, notice: "Pay attention to the road"
redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
Status est un paramètre défini par le programmeur qui utilise la méthode redirect_to. Au fur et à mesure que vous le lisez, vous pouvez voir quel rôle jouent les paramètres.
Rack::Utils.status_code(options.delete(:status))
Rack est un groupe de programmes qui servent d'intermédiaire entre les applications Rails et les serveurs d'applications. (Appelé middleware) status_code est une méthode définie dans une bibliothèque appelée Utils.
La valeur affectée au statut de la clé d'option par la méthode de suppression est transmise à la méthode status_code.
def status_code(status)
if status.is_a?(Symbol)
SYMBOL_TO_STATUS_CODE[status] || 500
else
status.to_i
end
end
Cette méthode est juste une méthode pour afficher la valeur de status. Il est appelé SYMBOL_TO_STATUS_CODE uniquement lorsqu'il est passé par Symbol (déterminé par la deuxième ligne est_a). Le hachage de conversion défini dans Rack :: Utils est utilisé.
La définition elle-même
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
[message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
}.flatten]
Ça ressemble à ça. Le hachage HTTP_STATUS_CODES également défini par ce code dans Rack :: Utils {: nom d'état HTTP Convertit en un tableau de hachage appelé => code d'état HTTP}.
En particulier
pry(main)> Rack::Utils::SYMBOL_TO_STATUS_CODE
=> {:continue=>100,
:switching_protocols=>101,
:processing=>102,
:early_hints=>103,
:ok=>200,
:created=>201,
:accepted=>202,
:non_authoritative_information=>203,
:no_content=>204,
:reset_content=>205,
:partial_content=>206,
:multi_status=>207,
:already_reported=>208,
:im_used=>226,
:multiple_choices=>300,
:moved_permanently=>301,
:found=>302,
:see_other=>303,
:not_modified=>304,
:use_proxy=>305,
:"(unused)"=>306,
:temporary_redirect=>307,
:permanent_redirect=>308,
:bad_request=>400,
:unauthorized=>401,
:payment_required=>402,
:forbidden=>403,
:not_found=>404,
:method_not_allowed=>405,
:not_acceptable=>406,
:proxy_authentication_required=>407,
:request_timeout=>408,
:conflict=>409,
:gone=>410,
:length_required=>411,
:precondition_failed=>412,
:payload_too_large=>413,
:uri_too_long=>414,
:unsupported_media_type=>415,
:range_not_satisfiable=>416,
:expectation_failed=>417,
:misdirected_request=>421,
:unprocessable_entity=>422,
:locked=>423,
:failed_dependency=>424,
:too_early=>425,
:upgrade_required=>426,
:precondition_required=>428,
:too_many_requests=>429,
:request_header_fields_too_large=>431,
:unavailable_for_legal_reasons=>451,
:internal_server_error=>500,
:not_implemented=>501,
:bad_gateway=>502,
:service_unavailable=>503,
:gateway_timeout=>504,
:http_version_not_supported=>505,
:variant_also_negotiates=>506,
:insufficient_storage=>507,
:loop_detected=>508,
:bandwidth_limit_exceeded=>509,
:not_extended=>510,
:network_authentication_required=>511}
#Exécutez sur la console Rails.
En d'autres termes, lorsque vous revenez à la définition de status_code
SYMBOL_TO_STATUS_CODE[status] || 500
Dans status :: not_found, "404" est renvoyé. S'il n'y a pas d'article correspondant, "500" est renvoyé.
Si une valeur telle que "404" est affichée dans les options [: status] au lieu du symbole, les 4ème à 5ème lignes renverront la valeur telle qu'elle est au format entier.
else
status.to_i
end
(Republier)
#Fileactionpack/lib/action_controller/metal/redirecting.rb, line 117
def _extract_redirect_to_status(options, response_status)
if options.is_a?(Hash) && options.key?(:status)
Rack::Utils.status_code(options.delete(:status))
elsif response_status.key?(:status)
Rack::Utils.status_code(response_status[:status])
else
302
end
end
Jusqu'à présent, j'ai lu ce que je fais sur la troisième ligne.
elsif response_status.key?(:status)
La méthode key? Rend cette instruction conditionnelle vraie lorsque l'argument response_status a un statut de clé. La méthode à exécuter est la même qu'avant.
Cela semble être une branche if pour permettre à l'état HTTP d'être renvoyé correctement, que la valeur d'état soit passée dans options ou response_status.
Si l'état HTTP à renvoyer n'est pas passé L'instruction else des lignes 6-7 renvoie 302. (Cela signifie «traitement de redirection».)
redirect_to (Republier)
# File actionpack/lib/action_controller/metal/redirecting.rb, line 56
def redirect_to(options = {}, response_status = {})
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(request, options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
end
Dans la 4ème ligne, j'ai décidé que le code d'état HTTP soit renvoyé du côté utilisateur.
self.location = _compute_redirect_to_location(request, options)
Une nouvelle méthode de rails est arrivée. La requête affectée ici est l'objet qui est créé à chaque fois sur le contrôleur. Chaque paramètre de la requête HTTP envoyée du côté utilisateur au côté application rails est stocké.
Quels types de paramètres existe-t-il? [Guide des rails](https://railsguides.jp/action_controller_overview.html#request%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3 % 83% 88% E3% 81% Réponse A8% E3% 82% AA% E3% 83% 96% E3% 82% B8% E3% 82% A7% E3% 82% FA% E3% 83% 88) Je suis.
Vous pouvez récupérer la valeur comme request.host.
La définition elle-même est faite sur le modèle ActionDispatch :: Request. Les méthodes disponibles pour ce modèle sont répertoriées ici (https://api.rubyonrails.org/classes/ActionDispatch/Request.html).
# File actionpack/lib/action_controller/metal/redirecting.rb, line 96
def _compute_redirect_to_location(request, options) #:nodoc:
case options
# The scheme name consist of a letter followed by any combination of
# letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
# characters; and is terminated by a colon (":").
# See https://tools.ietf.org/html/rfc3986#section-3.1
# The protocol relative scheme starts with a double slash "//".
when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/
options
when String
request.protocol + request.host_with_port + options
when Proc
_compute_redirect_to_location request, instance_eval(&options)
else
url_for(options)
end.delete("\00\\r\n")
end
Cette méthode générera l'URL vers laquelle rediriger. Le branchement conditionnel par l'instruction case est effectué par le contenu des opsions.
when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/
options
http://のように先頭に○○://とつく文字列のときに、この条件がtrueとなります。 Puisqu'il est jugé qu'il est sous forme d'URL, la valeur des options est renvoyée telle quelle.
when String
request.protocol + request.host_with_port + options
Appelé lorsque options est une chaîne. L'URL est générée sur la base de l'objet de requête qui stocke les informations de requête du côté utilisateur introduites précédemment. http: // et https: // sont stockés dans le protocole. host_with_port générera des hôtes après //. Enfin, des options sont données.
La méthode host_with_port est une méthode simple qui appelle les propriétés = host et port_string stockées dans l'objet de requête et les combine sous forme de chaîne.
# File actionpack/lib/action_dispatch/http/url.rb, line 250
def host_with_port
"#{host}#{port_string}"
end
when Proc
_compute_redirect_to_location request, instance_eval(&options)
Qu'est-ce que Proc
Un objet procédural qui objective un bloc avec un contexte (portée de variable locale ou cadre de pile). (https://docs.ruby-lang.org/ja/latest/class/Proc.html)[https://docs.ruby-lang.org/ja/latest/class/Proc.html]
redirect_to peut être utilisé au format bloc, et il est normal de reconnaître qu'il entrera dans cette branche lorsqu'un bloc est donné.
Par exemple
get 'jokes/:number', to: redirect { |params, request|
path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
"http://#{request.host_with_port}/#{path}"
}
Vous pouvez écrire quelque chose comme ça.
Lorsque le bloc est appelé, la méthode _compute_redirect_to_location est appelée de manière récursive. Pour les débutants, la récurrence est l'appel de la même méthode au sein d'une méthode. Par exemple
def method
method
end
Il a la forme. (Dans ce cas, ce sera une boucle infinie. Normalement, elle est écrite de manière à ne pas boucler indéfiniment avec if branch etc.)
(Republier)
\_compute_redirect_to_location request, instance_eval(&options)
instance_eval (& options) est assigné au deuxième terme de la méthode \ _compute_redirect_to_location (request, options).
Il y a un & devant les options, ce qui signifie attribuer un bloc. instance_eval est une méthode qui renvoie la sortie lorsque le code du bloc est exécuté.
Prenons l'exemple précédent (Republier)
get 'jokes/:number', to: redirect { |params, request|
path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
"http://#{request.host_with_port}/#{path}"
}
Dans ce cas, le code sur les 2ème et 3ème lignes sera exécuté, et par conséquent, l'URL commençant par http: // sur la 3ème ligne sera renvoyée sous forme de chaîne de caractères. En d'autres termes L'URL est affectée à la méthode \ _compute_redirect_to_location. L'instruction case est appelée et se ramifie aux conditions des 9ème à 10ème lignes mentionnées ci-dessus. (Republier)
when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/
options
else
url_for(options)
Pour résumer les conditions jusqu'à présent http://~といった具体的なURL、ファイル名を指す文字列、ブロックについて分岐されてきたが、いずれにも該当しない場合はこのelse文の内容が実行されることになります。
Ce qui ressort ici est la méthode url_for qui a également été utilisée dans link_to.
def url_for(options)
if options[:only_path]
path_for options
else
full_url_for options
end
end
url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080'
# => 'http://somehost.org:8080/tasks/testing'
url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true
# => '/tasks/testing#ok'
url_for :controller => 'tasks', :action => 'testing', :trailing_slash => true
# => 'http://somehost.org/tasks/testing/'
url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :number => '33'
# => 'http://somehost.org/tasks/testing?number=33'
(Citation) Générez une URL comme celle-ci.
end.delete("\00\\r\n")
Delete est appelé à la fin de la déclaration de cas.
Puisqu'il est appelé pour une chaîne de caractères, le comportement est différent de la suppression qui est apparue jusqu'à présent. Selon la référence Ruby
delete(*strs) -> String Génère et renvoie une chaîne avec les caractères contenus dans les chaînes supprimées.
La référence comprend également un article de référence pour le format strs. Je ne suis pas sûr car c'est moins important et je ne le comprends pas, Puisque \ r et \ n sont des caractères spéciaux qui représentent respectivement "retour" et "saut de ligne", on suppose qu'ils ont le sens de supprimer ces caractères qui sont mélangés avec l'URL. Alors je ne sais pas ce qu'est \ 00 , et je peux peut-être le séparer de \ 0, 0, \, r, \ n.
Jusqu'à présent, la méthode \ _compute_redirect_to_location.
redirect_to (Republier)
# File actionpack/lib/action_controller/metal/redirecting.rb, line 56
def redirect_to(options = {}, response_status = {})
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(request, options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
end
La ligne 4 détermine le code d'état HTTP à renvoyer à l'utilisateur après la redirection. L'URL de la destination de la redirection a été décidée sur la 5ème ligne.
6ème ligne
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
Maintenant, décidez des données html à renvoyer côté utilisateur. Ce code HTML ne sera pas affiché sur le navigateur de l'utilisateur car le processus de redirection est en fait effectué en fonction de la valeur de l'emplacement.
Ici, la valeur stockée dans self. ~ Est transmise au navigateur de l'utilisateur en tant que réponse HTTP. En regardant l'URL de la propriété d'emplacement (attribut) dans l'en-tête HTTP, le navigateur de l'utilisateur effectue à nouveau la demande.
Voir ici pour savoir comment le navigateur traite.
(Republier)
# File actionpack/lib/action_controller/metal/redirecting.rb, line 56
def redirect_to(options = {}, response_status = {})
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(request, options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
end
Lorsque redirect_to est appelé
J'ai trouvé que c'est le rôle de générer les données de réponse nécessaires pour cela, en supposant que le traitement réel est laissé au client (le navigateur utilisé par l'utilisateur) plutôt que d'effectuer le traitement dans cette méthode.
Si vous approfondissez votre compréhension du traitement effectué par les applications et les intergiciels Rails, il semble que vous serez en mesure de mettre en œuvre des traitements plus complexes.