Open8

Rails初学メモ

まっしゅるーむまっしゅるーむ

Remember me機能について

  1. ユーザーがログイン情報を入力してログインを試みる。
  2. サーバーはデータベースに対して認証を要求し、結果を受け取る。
  3. 認証に成功した場合、サーバーはデータベースから記憶トークンを要求し、それをブラウザにCookieとして設定する。これにより、ユーザーはホームページを表示できる。
  4. ユーザーがブラウザを閉じても、セッションは終了するが、Cookieは残る。
  5. ユーザーが再度ブラウザを開き、サイトにアクセスすると、ブラウザはCookie(ユーザーIDと記憶トークン)を含むリクエストをサーバーに送信する。
  6. サーバーはデータベースに対して記憶トークンの検証を要求し、結果に基づいてユーザーをログイン状態にするか、ログインページを表示するかを決定する。

まっしゅるーむまっしゅるーむ

user_idをcookieに保持する理由

user_idをCookieに保持する主な理由は、ユーザーがブラウザを閉じた後も、サーバーがユーザーを識別し、自動的にログイン状態を復元するため。
Remember me機能の実装において、user_idと記憶トークン(remember_token)を組み合わせて使用することで、セキュリティと利便性のバランスを取る。

以下にそのプロセスを詳しく記載。

  • ユーザー識別
    user_idはデータベース内の特定のユーザーを識別するために必要。
    ユーザーが再度ウェブサイトにアクセスした際に、サーバーはCookieに保存されたuser_idを使用して、そのユーザーのデータベースレコードを検索。

  • セキュリティ
    単独でuser_idをCookieに保存することはセキュリティリスクを伴うが、記憶トークンと組み合わせることでリスクを軽減する。
    サーバーは、Cookieに保存された記憶トークンがユーザーのデータベースレコードに保存されているハッシュ化されたトークンと一致するかを検証。
    この一致が確認できた場合のみ、ユーザーを認証し、ログイン状態を復元。

  • 利便性
    ユーザーが毎回ログイン情報を入力する手間を省き、ブラウザを閉じた後もスムーズにサイトを利用できる。特に、複数のデバイスやブラウザを使用するユーザーにとって、この機能は大きな利便性を提供する。

  • セッション管理
    user_idと記憶トークンの組み合わせは、セッション管理においても重要。
    サーバーはこれらの情報を使用して、ユーザーのセッションを識別し、管理。
    これにより、ユーザーが複数のタブやウィンドウでウェブサイトを利用していても、一貫したユーザー体験を提供できる。

まっしゅるーむまっしゅるーむ

Strong Parametersについて

コントローラー内で受け取ることが許可されているパラメータを明示的に指定できるパラメータ。
特定のアクションで必要とされるパラメータのみを許可し、
それ以外のパラメータが含まれている場合はエラーを発生させることで、不正なデータの受け入れを防ぐ。

Rails4.0から導入されたセキュリティ機能で、コントローラー層でのマスクアサインメントを防ぐために設計されたもの。

マスクアサインメント

ハッシュを用いてオブジェクトの複数の属性を一度に設定すること。
これには、セキュリティ上のリスクがあり、ユーザーがWebリクエストに管理者属性を不正に設定し、Webサイトの管理者権限を奪い取ることが可能。

params.require(:user).permit(:name, :email, :password, :password_confirmation)

:userキーを持つparamsハッシュから、名前、メールアドレス、パスワード、パスワード確認の各フィールドのみを取り出し、残りの不正なパラメータを無視。

Strong Parametersを効率的に使用するためには、user_paramsのような外部メソッドを定義。

def user_params
  params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
まっしゅるーむまっしゅるーむ

認可

認可(authorization)はそのユーザーが実行可能な操作を管理すること。

例えば、ユーザーAがユーザーBしか操作できないページに遷移する場合に認可処理をしないとユーザーAがユーザーBのページへ遷移できてしまい情報を変更できてしまう。

このようなケースでは、before_actionメソッドを使って処理を書く。

before_action

コントローラの全てのアクションが実行される前に何らかの処理を行う。
下記コードの例では、イメージなので本来であればbefore_actionメソッドで実行する処理は色々なケースを考慮してもっと複雑になる。

class UsersController < ApplicationController
  before_action :メソッド名
end
class UsersController < ApplicationController
  # 特定のアクションのときだけ使いたくない場合は、exceptオプションを用いる
  before_action :logged_in_user, only: [:edit, :update]

# something

  private
    def logged_in_user
      unless logged_in?
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end
end
まっしゅるーむまっしゅるーむ

パスワード再設定のフロー

  1. ユーザーがパスワードの再設定をリクエスト→ユーザーが送信したメールアドレスをキーにしてデータベースからユーザーを見つける
  2. 該当メールアドレスがデータベースにある場合、再設定用トークンと対応する再設定ダイジェストを生成
  3. 再設定用ダイジェストはデータベースに保存しておき、再設定用トークンはメールアドレスと一緒に、ユーザーに送信する有効化用メールのリンクに仕込んでおく
  4. ユーザーがメールのリンクをクリックしたら、メールアドレスをキーとしてユーザーを探し、データベース内に保存しておいた再設定用ダイジェストと比較する(トークンを認証する)
  5. 認証に成功したら、パスワード変更用のフォームをユーザーに表示する

Userテーブルに追加するカラム↓
reset_digest、reset_sent_at

まっしゅるーむまっしゅるーむ

マイクロポスト

用意するモデル
Micropost

id integer
content text
user_id integer
created_at datetime
updated_at datetime

Text型は、ある程度の文字列を格納するため。String型は、255文字まで。
(本番環境でもパフォーマンスの差は出ない。)

モデル作成

rails generate model Micropost content:text user:references

user:referencesはユーザーと1対1を示す。自動的に、インデックスと外部キー参照付きのuser_idカラムを追加できる。

マイグレファイルで下記を追加。
add_index :microposts, [:user_id, :created_at]
user_idcreated_atに対して、インデックスを貼ることで、user_idに関連するすべてのマイクロポストを作成時刻の逆順で取りやすくできたりする。
また、[:user_id, :created_at]で同じ配列に含めることで、Active Recordは両方のキーを同時に扱う 複合キーインデックスを作成。

belongs_to / has_many

belongs_to→1対1
has_many→1対多

上記を定義し関連付けることで、

@user = users(:michael)
@micropost = Micropost.new(content: "ほげ", user_id: @user.id)

@user = users(:michael)
@micropost = @user.microposts.build(content: "ほげ")

のように書けるようになる。

dependent: destroy

依存しているもの同士があり、片方が破棄された場合、もう片方を破棄する流れを自動的にやってくれる。

class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  ...
end

feed

whereメソッド

Micropost.where("user_id = ?", id)

?があることで、SQLに代入する前にidがエスケープされるため、SQLインジェクション を避けることができる。

画像アップロード

Railsに標準搭載されているActive Storageを使用。
has_one_attached メソッドやhas_many_attachedメソッドが提供されている。

rails active_storage:install

rails db:migrate

※Active Storageはファイルのバリデーションに関する機能を提供していないため、自前で用意する必要がある。

バリデーションのgem
active_storage_validations

画像リサイズ

ImageMagick

sudo apt-get -y install imagemagick

gem
image_processingmini_magick

まっしゅるーむまっしゅるーむ

フォロー

複合キーインデックス

add_index :relationships, [:follower_id, :followed_id], unique: true

followed_idfollower_idの組み合わせが必ずユニークになることを保証。

まっしゅるーむまっしゅるーむ

フィード

サブセレクト

SQLのサブセレクト(subselect)は、SQLクエリ内で別のSQLクエリを埋め込む方法。
サブセレクトは、外部クエリの条件や結果に基づいて内部クエリを実行し、その結果を外部クエリに組み込むことができる。データのフィルタリング、集計、結合、および他の多くの操作に使用される。

SELECT column1, column2, ...
FROM table_name
WHERE column_name IN (SELECT column_name FROM another_table WHERE condition);