[RUBY] Ich habe versucht zu verstehen, wie die Rails-Methode "redirect_to" definiert ist

Dies ist das zweite Projekt, in dem Sie lernen, wie man wie Rubin schreibt, indem Sie die Definition der Rails-Methode interpretieren. Das Thema ist diesmal redirect_to

Definition von 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

Die erste Zeile

def redirect_to(options = {}, response_status = {})

Nimmt zwei Argumente. In beiden Fällen wird ein leerer Hash zugewiesen, wenn kein Argument übergeben wird.

2. Zeile

raise ActionControllerError.new("Cannot redirect to nil!") unless options

Fehler auslösen, wenn die Optionen leer sind. Übrigens behandelt Ruby alles außer false und nil als true, sodass ein leerer Hash {} keinen Fehler verursacht. Ein Fehler tritt auf, wenn der Benutzer es wagt, nil / false zuzuweisen.

3. Zeile

raise AbstractController::DoubleRenderError if response_body

Ein Fehler tritt auf, wenn Sie bereits eine HTTP-Antwort erhalten haben. Ich weiß nicht, wie response_body hier zugewiesen wird, aber es scheint einen Fehler zurückzugeben, wenn mehrere HTTP-Kommunikationen gleichzeitig ausgetauscht werden.

4. Zeile

self.status = _extract_redirect_to_status(options, response_status)

Auch diesmal ist eine neue Methode herausgekommen.

\ _extract_redirect_to_status Methode

Definition

#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

2. Zeile

if options.is_a?(Hash) && options.key?(:status)

Ein Punkt der if-Bedingung is_a? Methode ist der Typ, in dem der Typ des Empfängers (hier "Optionen") in Klammern angegeben ist. Eine Methode, die true zurückgibt, wenn sie übereinstimmt (hier "Hash").

Die beiden Elemente Schlüssel? der if-Bedingung sind die Schlüssel, deren Namen in Klammern angegeben sind. Eine Methode, die true zurückgibt, wenn dies der Fall ist.

Mit anderen Worten, wenn das an redirect_to übergebene Argument ein Hash ist und den Schlüsselstatus hat, wird der Inhalt der if-Anweisung ausgeführt. Wie Sie im eingangs erwähnten Rails-Dokument sehen können

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 ist ein Parametersatz des Programmierers, der die Methode redirect_to verwendet. Während Sie es lesen, können Sie sehen, welche Rolle die Parameter spielen.

3. Zeile

Rack::Utils.status_code(options.delete(:status))

Rack ist eine Gruppe von Programmen, die als Vermittler zwischen Rails-Anwendungen und Anwendungsservern fungieren. (Middleware genannt) status_code ist eine Methode, die in einer Bibliothek namens Utils definiert ist.

Der Wert, der dem Optionsschlüsselstatus von der Löschmethode zugewiesen wurde, wird an die status_code-Methode übergeben.

status_code Methode

def status_code(status)
  if status.is_a?(Symbol)
    SYMBOL_TO_STATUS_CODE[status] || 500
  else
    status.to_i
  end
end

Diese Methode ist nur eine Methode zum Anzeigen des Statuswerts. Es heißt SYMBOL_TO_STATUS_CODE nur, wenn es von Symbol (bestimmt durch is_a) übergeben wird. Der in Rack :: Utils definierte Konvertierungs-Hash wird verwendet.

Die Definition selbst

SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
  [message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
}.flatten]

Es sieht aus wie das. Der Hash HTTP_STATUS_CODES wird ebenfalls durch diesen Code in Rack :: Utils {: HTTP-Statusname definiert In ein Hash-Array mit dem Namen => HTTP-Statuscode} konvertieren.

Speziell

 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}
#Führen Sie es auf der Rails-Konsole aus.

Mit anderen Worten, wenn Sie zur Definition von status_code zurückkehren

SYMBOL_TO_STATUS_CODE[status] || 500

In status :: not_found wird "404" zurückgegeben. Wenn kein entsprechender Artikel vorhanden ist, wird "500" zurückgegeben.

Wenn ein Wert wie "404" in den Optionen [: status] anstelle des Symbols angezeigt wird, gibt die 4. bis 5. Zeile den Wert im Ganzzahlformat zurück.

else
  status.to_i
end

\ _extract_redirect_to_status Methode

(Erneut veröffentlichen)

#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

Bisher habe ich in der dritten Zeile gelesen, was ich mache.

4. Zeile

elsif response_status.key?(:status)

Die key? -Methode macht diese bedingte Anweisung wahr, wenn das Argument response_status einen Schlüsselstatus hat. Die auszuführende Methode ist dieselbe wie zuvor.

Es scheint sich um eine if-Verzweigung zu handeln, mit der der HTTP-Status korrekt zurückgegeben werden kann, unabhängig davon, ob der Statuswert in options oder response_status übergeben wird.

Wenn der zurückzugebende HTTP-Status nicht übergeben wird Die else-Anweisung in den Zeilen 6-7 gibt 302 zurück. (Es bedeutet "Weiterleitungsverarbeitung".)

redirect_to (Erneut veröffentlichen)

# 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

In der 4. Zeile habe ich beschlossen, den HTTP-Statuscode an die Benutzerseite zurückzugeben.

5. Zeile

self.location = _compute_redirect_to_location(request, options)

Eine neue Schienenmethode ist angekommen. Die hier zugewiesene Anforderung ist das Objekt, das jedes Mal auf der Steuerung erstellt wird. Jeder Parameter der HTTP-Anforderung, die von der Benutzerseite an die Rails-Anwendungsseite gesendet wird, wird gespeichert.

Welche Parameter gibt es? [Rails Guide](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% A8Response% E3% 82% AA% E3% 83% 96% E3% 82% B8% E3% 82% A7% E3% 82% AF% E3% 83% 88) Ich bin.

Sie können den Wert wie request.host abrufen.

Die Definition selbst erfolgt im ActionDispatch :: Request-Modell. Die für dieses Modell verfügbaren Methoden sind hier aufgelistet (https://api.rubyonrails.org/classes/ActionDispatch/Request.html).

\ _ Compute_redirect_to_location-Methode

Definition

# 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

Diese Methode generiert die URL, zu der umgeleitet werden soll. Die bedingte Verzweigung durch die case-Anweisung erfolgt durch den Inhalt der Optionen.

Zeilen 9-10

when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/
  options

http://のように先頭に○○://とつく文字列のときに、この条件がtrueとなります。 Da davon ausgegangen wird, dass es sich um eine URL handelt, wird der Wert der Optionen unverändert zurückgegeben.

Zeilen 11-12

when String
  request.protocol + request.host_with_port + options

Wird aufgerufen, wenn options eine Zeichenfolge ist. Die URL wird basierend auf dem Anforderungsobjekt generiert, in dem die Anforderungsinformationen der zuvor eingeführten Benutzerseite gespeichert sind. http: // und https: // werden im Protokoll gespeichert. host_with_port generiert Hosts nach //. Schließlich werden Optionen angegeben.

Die Methode host_with_port ist eine einfache Methode, die die im Anforderungsobjekt gespeicherten Eigenschaften = host und port_string aufruft und als Zeichenfolge kombiniert.

# File actionpack/lib/action_dispatch/http/url.rb, line 250
def host_with_port
  "#{host}#{port_string}"
end

Zeilen 13-14

when Proc
  _compute_redirect_to_location request, instance_eval(&options)

Was ist Proc

Ein prozedurales Objekt, das einen Block mit einem Kontext objektiviert (lokaler Variablenbereich oder Stapelrahmen). (https://docs.ruby-lang.org/ja/latest/class/Proc.html)[https://docs.ruby-lang.org/ja/latest/class/Proc.html]

redirect_to kann im Blockformat verwendet werden, und es ist in Ordnung zu erkennen, dass es in diesen Zweig eintritt, wenn ein Block angegeben wird.

Zum Beispiel

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}"
  }

Sie können so etwas schreiben.

Wenn der Block aufgerufen wird, wird die Methode _compute_redirect_to_location rekursiv aufgerufen. Für Anfänger ist Wiederholung der Aufruf derselben Methode innerhalb einer Methode. Zum Beispiel

def method
  method
end

Es ist wie geformt. (In diesem Fall handelt es sich um eine Endlosschleife. Normalerweise wird sie so geschrieben, dass sie nicht unendlich mit if branch usw. wiederholt wird.)

(Erneut veröffentlichen)

\_compute_redirect_to_location request, instance_eval(&options)

instance_eval (& options) wird dem zweiten Term der Methode \ _compute_redirect_to_location (request, options) zugewiesen.

Vor den Optionen steht ein &, was bedeutet, dass ein Block zugewiesen wird. instance_eval ist eine Methode, die die Ausgabe zurückgibt, wenn der Code im Block ausgeführt wird.

Betrachten wir das vorherige Beispiel (Erneut veröffentlichen)

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}"
  }

In diesem Fall wird der Code in der 2. und 3. Zeile ausgeführt, und als Ergebnis wird die URL, die mit http: // in der 3. Zeile beginnt, als Zeichenfolge zurückgegeben. Mit anderen Worten Die URL wird der Methode \ _compute_redirect_to_location zugewiesen. Die case-Anweisung wird aufgerufen und verzweigt sich zu den oben genannten Bedingungen in der 9. bis 10. Zeile. (Erneut veröffentlichen)

when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/
  options

Zeilen 15-16

else
  url_for(options)

Um die bisherigen Bedingungen zusammenzufassen http://~といった具体的なURL、ファイル名を指す文字列、ブロックについて分岐されてきたが、いずれにも該当しない場合はこのelse文の内容が実行されることになります。

Was hier herauskommt, ist die url_for-Methode, die auch in link_to verwendet wurde.

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'

(Zitat) Generieren Sie eine URL wie diese.

17. Zeile

end.delete("\00\\r\n")

Löschen wird am Ende der case-Anweisung aufgerufen.

Da eine Zeichenfolge aufgerufen wird, unterscheidet sich das Verhalten von dem bisher aufgetretenen Löschen. Laut der Ruby-Referenz

delete(*strs) -> String Erzeugt eine Zeichenfolge und gibt sie zurück, wobei die in strs enthaltenen Zeichen entfernt werden.

Die Referenz enthält auch einen Referenzartikel für das strs-Format. Ich bin mir nicht sicher, weil es weniger wichtig ist und ich es nicht verstehe. Da \ r und \ n Sonderzeichen sind, die "return" bzw. "line feed" darstellen, wird angenommen, dass sie die Bedeutung haben, diese mit url gemischten Zeichen zu löschen. Dann weiß ich nicht, was \ 00 \ ist, und vielleicht kann ich es von \ 0, 0, \, r, \ n trennen.

Bisher die Methode \ _compute_redirect_to_location.

redirect_to (Erneut veröffentlichen)

# 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

Zeile 4 bestimmt den HTTP-Statuscode, der nach der Umleitung an den Benutzer zurückgegeben werden soll. Die URL des Weiterleitungsziels wurde in der 5. Zeile festgelegt.

  1. Zeile
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"

Entscheiden Sie nun, welche HTML-Daten an die Benutzerseite zurückgegeben werden sollen. Dieses HTML wird im Benutzerbrowser nicht angezeigt, da der Umleitungsprozess tatsächlich basierend auf dem Standortwert ausgeführt wird.

Hier wird der in self gespeicherte Wert als HTTP-Antwort an den Browser des Benutzers übergeben. Wenn Sie sich die URL der Location-Eigenschaft (Attribut) im HTTP-Header ansehen, stellt der Browser des Benutzers die Anforderung erneut.

Informationen zur Verarbeitung des Browsers finden Sie unter hier.

Zusammenfassung

(Erneut veröffentlichen)

# 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

Wenn redirect_to aufgerufen wird

  1. Fehler, wenn die Optionen Null enthalten
  2. Fehler, wenn bereits eine Antwort generiert wurde
  3. Speichern Sie den Status der an den Benutzer zurückgegebenen HTTP-Antwort (200: Erfolg, 404: Nicht gefundener Fehler usw.) im Antwortobjekt.
  4. Speichern Sie die Umleitungsziel-URL im Antwortobjekt
  5. Speichern Sie HTML-Daten in einem Antwortobjekt (das jedoch im Grunde nie angezeigt wird).

Impressionen

Ich fand, dass es die Aufgabe ist, die dafür erforderlichen Antwortdaten zu generieren, vorausgesetzt, dass die eigentliche Verarbeitung dem Client (dem vom Benutzer verwendeten Browser) überlassen bleibt, anstatt die Verarbeitung in dieser Methode durchzuführen.

Wenn Sie Ihr Verständnis für die Verarbeitung von Rails-Anwendungen und Middleware vertiefen, können Sie anscheinend eine kompliziertere Verarbeitung implementieren.

Recommended Posts

Ich habe versucht zu verstehen, wie die Rails-Methode "redirect_to" definiert ist
Ich habe versucht zu verstehen, wie die Rails-Methode "link_to" definiert ist
Ich habe versucht, die Methode zu erklären
[Schienen] Verwendung der Kartenmethode
[Rails] Ich habe versucht, die Version von Rails von 5.0 auf 5.2 zu erhöhen
[Rails] Ich weiß nicht, wie ich das Modell verwenden soll ...
[Rails] Ich habe zum ersten Mal versucht, die button_to-Methode zu verwenden
Verwendung der link_to-Methode
Verwendung der include? -Methode
Verwendung der Methode form_with
[Rails] Ich habe versucht, die Anwendung zu löschen
Daten sortieren Absteigend, aufsteigend / Schienen
Ich habe versucht, die Bildvorschau mit Rails / jQuery zu implementieren
[Rails] So lassen Sie die Anzeige der Zeichenfolge der link_to-Methode weg
[Java] Ich habe versucht, mit der Grabmethode ein Labyrinth zu erstellen ♪
Ich habe versucht, die verwendeten Methoden zusammenzufassen
[Java] Verwendung der toString () -Methode
Ich wollte der Methode @VisibleForTesting hinzufügen
Ich war süchtig nach der Rollmethode
Ich habe versucht, das Iterator-Muster zu implementieren
Ich habe versucht, die Stream-API zusammenzufassen
[Ruby on Rails] Verwendung von redirect_to
Was ist Docker? Ich habe versucht zusammenzufassen
Speicherort der Methodendefinition Zusammenfassung der zu überprüfenden Informationen Wenn im Projekt und in Rails / Gem definiert
[Rails] Verwendung der Hilfsmethode, Confimartion
[Einführung in Java] Ich habe versucht, das Wissen zusammenzufassen, das ich für wesentlich halte
[Rails] So lösen Sie die Zeitverzögerung von created_at nach der Speichermethode
[Rails] So bestimmen Sie das Ziel anhand von "Rails-Routen"
Ausgabe der Verwendung der Slice-Methode
Code zum Verbinden von Rails 3 mit PostgreSQL 10
Verwendung der replace () -Methode (Java Silver)
Ich habe versucht, Tomcat so einzustellen, dass das Servlet ausgeführt wird.
So überprüfen Sie Rails-Befehle im Terminal
[Ruby-Grundlagen] Verwendung der Slice-Methode
[Rails / ActiveRecord] Ich möchte den Wert überprüfen, bevor der Typ konvertiert wird (_before_type_cast).
[JavaScript] Der stärkste Fall, als ich versuchte, die Teile zusammenzufassen, die ich nicht verstehe
[Rails] So bedienen Sie die in der Hauptanwendung verwendete Hilfsmethode mit Administrate
[JDBC ③] Ich habe versucht, mithilfe von Platzhaltern und Argumenten Eingaben über die Hauptmethode vorzunehmen.
[Rails] So stellen Sie über den HTTP-Client eine Verbindung zu einer externen API her (ich habe versucht, eine Verbindung zur Qiita-API herzustellen)
So stellen Sie die Anzeigezeit in Rails auf japanische Zeit ein
Wie weit ist die richtige Antwort, um den Prozess zu teilen?
[Rails] So verwenden Sie die Hilfsmethode von devise before_action: authenticate_user!
Wie schreibe ich Rails
[Ruby on Rails] So ändern Sie den Spaltennamen
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
[Rails] So ändern Sie den Spaltennamen der Tabelle
So deinstallieren Sie Rails
Rails6 Ich habe versucht, Docker in eine vorhandene Anwendung einzuführen
Ich möchte die Hauptmethode mit Reflektion aufrufen
[Rails] So erhalten Sie den Inhalt starker Parameter