カニゲーム攻略日記ブログ

beatmaniaIIDXやハースストーンなどのゲーム攻略日記。主にまったり勢。2016年にIIDX皆伝になった

progate Ruby on Rails 5講座目

progate Ruby on Rails 5講座目

Progateの、Ruby on Rails
5講座目をやったメモ
気になったことをメモしたのでprogateと関係ないこともある

余談

明日から久しぶりに仕事だー
早めに帰りたい

結局のところ、積み重ね
分からないことを疎かにせず、ちょっと調べるのが大事か

バリデーション

モデル

空の投稿を防ぐバリデーションは
{presence: true}

class Post < ApplicationRecord
    validates :content, {presence: true}
end

文字数チェックバリデーションは
{length: {maximun: 140}}

class Post < ApplicationRecord
    validates :content, {length: {maximum: 140}}
end

コントローラーで判断

if @post.save

else

end

バリデーションの流れ

  1. ユーザーが情報を入力、フォームへと送る。
  2. コントローラーが情報を受け取り、モデルへ渡す。
  3. モデルに設けられたバリデーション、その目覚め。
  4. 検証のプロセスが始まり、データに目を光らせる。

    4.1. バリデーションが通り、データは正当と判断。 次の処理へ進み、データベースへ保存。 4.2. バリデーションに引っかかり、不正が発覚。 エラーメッセージを生成し、ユーザーに知らせる。

  5. バリデーション終わり、情報の安全を確かめる。 そして、その結果に応じて、処理は分岐。

なぜpresenceという名前?

「存在する(present)」ことを確認するためですわ。

カラムの名前の由来は?

古代ギリシャやローマの建築物に見られる柱(column)に由来していますわ。データベースのテーブルは行と列の2次元の構造を持っており、それぞれの列が「カラム」と呼ばれるのです。

validateの名前の由来は?

英語の "validate" という単語から来ていますわ。"validate" は、検証する、正当性を確認する、承認する、といった意味がございます。

ハッシュとは?

ハッシュは、キーと値の組み合わせで構成されるデータ構造です。他の言語では、連想配列、辞書、マップなどとも呼ばれることがあります。ハッシュは、キーを使って値に簡単にアクセスできるように設計されています。

Rubyでハッシュを表現する場合、以下のように中括弧({})を使用してキーと値を定義します。

hash_example = {
  'key1' => 'value1',
  'key2' => 'value2',
  'key3' => 'value3'
}

ハッシュから値を取得するには、以下のようにキーを指定します:

hash_example['key1'] #=> 'value1'

ハッシュの名前の由来は?

ハッシュの名前は、ハッシュ関数というアルゴリズムから由来しています。
ハッシュ関数を使うと、データの追加、検索、削除などの操作が高速に実行できるため、このデータ構造が「ハッシュ」と呼ばれています。その根底にあるのは、ハッシュ関数を使った効率的なデータ管理です。

railsの「validates :content, {presence: true}」の内部動作はどうなっている?

Railsにおけるバリデーションの内部動作について、validates :content, {presence: true} を例に解説いたします。

  1. まず、validatesメソッドは、Active Recordにおいてバリデーションを定義するためのメソッドです。
  2. :contentは、バリデーションが適用される属性(カラム)を示しています。この場合、contentカラムにバリデーションが適用されます。
  3. {presence: true}は、バリデーションのオプションを表しています。ここでは、presenceバリデーションが適用されることを示しています。
  4. presence: trueのバリデーションは、属性(カラム)の値が存在することをチェックするバリデーションです。値が存在しない場合(空の場合)、バリデーションエラーが発生します。

バリデーションが実行されるタイミングは、レコードが保存される際に行われます。具体的には、savecreateupdateメソッドが呼び出されるときにバリデーションが実行されます。

validatesメソッド解析依頼

ソースコードを解説してもらった
まだすべては理解できないのだが
複数のハッシュをeachで処理しているから、以下のように複数引数を取れる
validates :content, {presence: true , length: {maximum: 140}}

https://railsdoc.com/validation

      def validates(*attributes)
        defaults = attributes.extract_options!.dup
        validations = defaults.slice!(*_validates_default_keys)

        raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
        raise ArgumentError, "You need to supply at least one validation" if validations.empty?

        defaults[:attributes] = attributes

        validations.each do |key, options|
          key = "#{key.to_s.camelize}Validator"

          begin
            validator = key.include?("::") ? key.constantize : const_get(key)
          rescue NameError
            raise ArgumentError, "Unknown validator: '#{key}'"
          end

          next unless options

          validates_with(validator, defaults.merge(_parse_validates_options(options)))
        end
      end

以下は、上記のRubyコードの1行毎の解説です。

  1. def validates(*attributes)

    • validatesメソッドを定義します。可変長引数*attributesで任意の数の属性を受け取ります。
  2. defaults = attributes.extract_options!.dup

    • extract_options!を使って、属性の配列からオプションハッシュを取り出し、defaultsに複製を代入します。
  3. validations = defaults.slice!(*_validates_default_keys)

    • _validates_default_keysメソッドが返すキーを使って、defaultsからバリデーションに関する部分だけを取り出し、validationsに代入します。
  4. raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?

    • 属性が一つも指定されていない場合、引数エラーを発生させます。
  5. raise ArgumentError, "You need to supply at least one validation" if validations.empty?

    • バリデーションが一つも指定されていない場合、引数エラーを発生させます。
  6. defaults[:attributes] = attributes

    • defaultsハッシュに:attributesキーを追加し、その値としてattributesを設定します。
  7. validations.each do |key, options|

    • validationsハッシュの各要素に対してブロックを実行します。
  8. key = "#{key.to_s.camelize}Validator"

    • キーを文字列に変換し、キャメルケースに変換して"Validator"を付け加えます。
  9. begin

    • 例外処理の開始。
  10. validator = key.include?("::") ? key.constantize : const_get(key)

    • キーに"::"が含まれているかどうかで条件分岐し、対応するバリデータクラスをvalidatorに代入します。
  11. rescue NameError

    • NameError例外が発生した場合の処理を記述します。
  12. raise ArgumentError, "Unknown validator: '#{key}'"

    • ArgumentErrorを発生させ、未知のバリデータであることを通知します。
  13. end

    • 例外処理の終了。
  14. next unless options

  15. validates_with(validator, defaults.merge(_parse_validates_options(options)))

    • validates_withメソッドを呼び出し、バリデータオブジェクトとオプションをマージした引数を渡します。
  16. end

    • validations.eachブロックの終了。
  17. end

    • `validates

railsでredirect_toはなぜcontrollerに書く?

Railsでは、コントローラがアプリケーションの流れを制御する役割を担っております。redirect_toは、ユーザーを別のページに転送することでアプリケーションのフローを制御するために使用される方法ですの。

コントローラにredirect_toを書くことで、特定のアクションが完了した後、ユーザーを適切なページに誘導することができます。これにより、アプリケーションの全体的な流れがスムーズに進むのですわ💫。

redirect_toをviewには書かない?

Railsアプリケーションにおいて、私たちの魔法の世界と同じく、すべてには役割と秩序がございますの。それはまさに、Model-View-Controller(MVC)という設計パターンと呼ばれるもので、まるでお城のように美しく整った世界が広がっていますわ。

Viewは、まるで舞踏会のドレスのごとく、美しい情報の表示を担っております。それに対して、Controllerはまさに魔法使いが振るう杖のように、アプリケーションの流れを見事に制御してくださるのです。

redirect_toは、アプリケーションの舞台を変える魔法のようなものでございまして、Controllerが持つべき力であります。Viewにその力を持たせてしまうと、まるでドレスが杖を振るわんばかりの異常事態となってしまい、美しい世界が乱れてしまうのですわ。

そのため、Viewは美しい情報の表示に専念し、アプリケーションの制御はControllerが見事に手綱を握ることで、まるでお城の舞踏会のように美しく秩序だった世界が維持されるのですわ✨。

redirect_toはアクションを経由している?

はい、その通りですわ。redirect_toは、Railsアプリケーションにおいて、あるアクションから別のアクションへと制御を移動させる役割を果たしています。リダイレクトする際に、HTTPレスポンスのステータスコード302 Foundとして設定され、ブラウザは新たなアクションにアクセスするよう指示されます。

このように、redirect_toはアクション間で制御を移動させ、適切なアクションが呼び出されるようにすることで、アプリケーションの流れをスムーズに進める役割を果たしております。

  1. ユーザーが特定のアクション(例えば、createアクション)をリクエストする。
  2. コントローラがそのアクションを処理する。ここでredirect_toが呼び出される場合がある。
  3. redirect_toが呼び出されると、新しいアクション(例えば、indexアクション)にリダイレクトされる。
  4. リダイレクト先のアクションが実行され、対応するビューが表示される。

このプロセスは以下のような図式で表現できます。

[ユーザー] -> [リクエスト] -> [コントローラのアクション1] -> [redirect_to] -> [コントローラのアクション2] -> [ビュー]

この図式により、リダイレクトがコントローラ内のアクション間で制御を移動させていることがお分かりいただけるかと存じます。

302 Foundの簡単な説明

302 FoundはHTTPステータスコードのひとつで、リソースが一時的に別の場所に移動されていることを示すものですわ。つまり、クライアントは新しいURLに従ってリダイレクトされるのです。

具体例としては、オンラインショッピングのウェブサイトが考えられますわね。
お客様がログイン後、商品のページにアクセスしようとすると、ウェブサイトは一度カートのページにリダイレクトさせ、そこから商品ページへと移動する、といった具合です。
この際に、302 Foundステータスコードが使用されることがあります。このようなリダイレクトは一時的なもので、クライアントが新しいURLに従ってリソースにアクセスすることが期待されるのですわ。

投稿失敗時に直前の投稿内容を表示したい

投稿失敗時に直前の投稿内容が消える 例

  1. ビュー:不正な投稿内容(文字数オーバーなど)を編集して保存ボタン押す
  2. コントローラー:updateアクション:redirect_toでeditアクションに転送
  3. コントローラー:editアクション:データベースから編集前のデータを取得する
  4. ビュー:編集前のデータを表示する

renderでeditアクションをとばす

  1. ビュー:不正な投稿内容(文字数オーバーなど)を編集して保存ボタン押す
  2. コントローラー:updateアクション:params[:content]から直前の投稿内容を取得して、renderでビューへ
  3. ビュー:直前の投稿内容を表示する

renderの書き方

render("posts.edit")  #ビューファイルを指定

ビューファイル例「posts/edit.html.erb」

redirect_toとrenderを図で

図で説明するにはテキストのみの形式が制約になりますが、要点を説明いたします。以下は、redirect_torender の違いを表す簡単な説明です。

[ クライアント ]               [ サーバー ]
    |                              |
    |--- 1. リクエスト ----------> |
    |                              |
    |                              |--- 2. コントローラ
    |                              |        |
    |                              |        |--- (a) redirect_to
    |                              |        |        |
    |                              |        |        |--- 3a. 302応答 (別URL)
    |                              |        |         <---
    |                              |        |
    |                              |        |--- (b) render
    |                              |                 |
    |                              |                 |--- 3b. 200応答 (HTML)
    |                              |                  <---
    |                              |
    |--- 4. レスポンス受信 -------< |
    |                              |
  1. クライアントからサーバーへリクエストが送信されます。
  2. サーバー側でコントローラがリクエストを処理します。
    • (a) コントローラで redirect_to が使われる場合: 3a. サーバーは、302 Found 応答 (リダイレクト) と新しいURLをクライアントに返します。
    • (b) コントローラで render が使われる場合: 3b. サーバーは、200 OK 応答とHTMLコンテンツをクライアントに返します。
  3. クライアントがレスポンスを受信し、画面に表示されます。

redirect_to は、新しいURLにリダイレクトさせるために使われ、ブラウザに新しいリクエストが送信されます。一方、render は、現在のリクエストに対してHTMLを生成し、ブラウザにそのまま返します。このため、リダイレクトが発生しないため、リクエストとレスポンスのサイクルはより短くなります。

新しいURLへのリダイレクトを行うと何故、関連するコントローラの別のアクションを経由する?

新しいURLへのリダイレクトが行われると、実際にはブラウザに新しいURLへのリクエストを行うよう指示が出されます。その新しいリクエストがRailsアプリケーションに届くと、Railsのルーティングシステムは、そのリクエストに対応するコントローラとアクションを見つけるために働きます。

つまり、リダイレクトを行うと、ブラウザが新しいリクエストを送信するため、結果として関連するコントローラの別のアクションが実行されることになります。これは、リダイレクトがHTTPレベルで行われるため、Railsアプリケーション内でアクションを直接呼び出すのではなく、新しいリクエストが生成され、それに応じて適切なアクションが実行されるためです。

redirect_toの場合、Railsルーターが新しいアクション(Action)にリクエストをルーティングし、そのアクションがViewを表示しています。一方、renderの場合、同じアクションの中でViewが表示されるだけで、新しいリクエストやアクションの呼び出しは行われません。

何故301じゃなくて302?

HTTPステータスコードには、301と302のようなさまざまな数字がありますが、これらはウェブサーバーからの応答を示すために使用されます。

  • 301 Moved Permanently:これは、指定されたリソースが永久的に新しいURLに移動されたことを示します。ウェブサーバーは、クライアントに対して新しいURLにアクセスするよう指示します。つまり、301は「もうここにはいないんだから、新しい場所に行ってね!」と言っているようなものです。

  • 302 Found:これは、リソースが一時的に別のURLに移動されたことを示します。クライアントは、新しいURLにアクセスすることが期待されますが、将来的には元のURLに戻る可能性があります。302は、「今はちょっと違う場所にいるけど、また戻るかもしれないからね!」と言っているようなものです。

さて、redirect_toで302を使う理由ですが、それは主に一時的なリダイレクトがよく使われるからです。例えば、フォームを送信した後にユーザーを別のページにリダイレクトさせる場合などです。301を使うと、ブラウザがリダイレクト先を永久的にキャッシュしてしまうため、一時的なリダイレクトには適していません。

あのさぁ、数字ってやつは、いつもいろいろと面倒くさい問題を引き起こすんだよね。だけど、今回の質問については、302が一時的なリダイレクトを示すから、それを使っているんだってことがわかったね!

HTTPステータスコードのことを知ってないと?

かのHTTPステータスコード、知るべきかもしれぬ

必要ではない、全てのコードを学ぶことは しかし、重要なものは、知っておくべきだろう

200、404、500、そして302 これらのコード、心に刻んでおくれ

エラーメッセージ

バリデーションに失敗すると自動的にエラーメッセージが生成される(配列)
@post.error.full_messages

<% @post.errors.full_messages.each do |message| %>
  <%= message %>
<% end %>

フラッシュ

WEBページに1度だけ出るメッセージ

変数flash

  1. コントローラー:

      flash[:notice] = "文字"  
    
  2. ビュー:layouts

       <% if flash[:notice] %>
         <div class="flash">
           <%= flash[:notice] %>
         </div>
       <% end %>
    

上記のdiv必要?

このdivは必要、フラッシュメッセージを見せるため。
通知を美しく、分かりやすく伝えるのだ。

flash[:notice] のnotice?

"notice"、通知の名にふさわしく、 フラッシュメッセージの一種なり。 成功や情報、やさしい知らせを伝える役割を持つ。

flashハッシュにキーとして登場し、 値としてメッセージを持つことで、 画面に知らせを映す機会を与える。

他にも、"alert" や "error" といったキーが存在し、 異なる目的、異なる種類のメッセージを伝える。 それらは警告や失敗を伝える役割を果たす。