【Rails】URLをid以外のカラム名にする方法(paramオプション)
以下のようにresourceのid
を使ったURLでなく、登録したアカウント名でURLを設定していく方法を説明する。
ページ | :id を使用したURL | param: :account を使用したURL |
---|---|---|
ユーザー情報表示ページ | http://example.com/users/1 |
http://example.com/users/ganmo |
ユーザー情報編集ページ | http://example.com/users/1/edit |
http://example.com/users/ganmo/edit |
テーブル設定
Userテーブルにaccount
カラムがあることを前提とする。
accountカラムがデータベース内で重複しないようにユニーク制約を追加する。
ターミナルで以下を入力。
rails g migration AddUniqueIndexToUsers
マイグレーションファイルに以下を追加する。
class AddUniqueIndexToUsersAccount < ActiveRecord::Migration[6.1]
def change
add_index :users, :account, unique: true
end
end
マイグレーションを実行する。
これで、同じアカウント名を複数回登録できないようする。
ルーティングの設定
param
オプションを使ってアカウント名をURLの一部にする設定をする。
resources :users, param: :account, only: [:show, :edit, :update]
これでusers/:account
でアクセスできるようになる。
モデルの設定
class User < ApplicationRecord
:
# idの代わりにアカウントを使用
def to_param
account
end
# 英数字(小文字)と"ハイフン(-)" "アンダーバー(_)"のみ許可
validates :account,
format: { with: /\A[a-z0-9_-]+\z/ },
length: { minimum: 3, maximum: 25 }
:
-
def to_param
このメソッドを使うことで、IDでなく、アカウント名でURLを作るための処理をする。 -
validates :account
アカウント名が、英小文字(a-z)、数字(0-9)、ハイフン(-)、アンダースコア(_)のみの登録になるようにバリデーションを設定。
また、アカウント名の長さを3文字以上25文字以下にする。
コントローラの設定
パラメータが:id
から:account
に変わるため、コントローラを対応できるようにする。
- 通常
class Public::UsersController < ApplicationController
:
def show
@user = User.find(params[:id]
end
:
- 変更後
class Public::UsersController < ApplicationController
:
def show
# accountをシンボル化する
account_str = params[:account] # ユーザーからの入力を取得
sanitized_account_str = account_str.gsub(/[^a-zA-Z0-9_]/, '') # 文字列から不要な文字(コロン以外の特殊文字など)を削除
account_sym = sanitized_account_str.to_sym # 文字列をシンボルに変換
@user = User.find_by(account: account_sym) # サニタイズされたシンボルを使用してクエリを実行
:
end
-
account_str = params[:account]
URLのパラメータとして受け取ったアカウント名を、params
から取得するようにする。params
には、URLに含まれる情報(クエリパラメータやパスの一部など)が格納されている。 -
sanitized_account_str = account_str.gsub(/[^a-zA-Z0-9_]/, '')
アカウント名がURLに直接公開されてしまうため、サニタイズしてセキュリティ対策をする。
ここでは、-
と_
を含む英数字以外の文字を削除することで、悪意のあるユーザーが特殊な記号やコードを入力して、サーバーやデータベースに対する攻撃を防ぐ。 -
account_sym = sanitized_account_str.to_sym
サニタイズされたアカウント名をシンボルに変換する。シンボル化とは、名前を効率的に管理するための方法のこと。文字列に似たもので、プログラム内での操作を高速化し、メモリ効率をよくする。 -
@user = User.find_by(account: account_sym)
シンボル化されたアカウント名を使って、User
モデルからデータベースを検索して該当するユーザー情報を取得する。検索条件としてaccount: account_sym
を指定し、シンボル化されたアカウント名に一致するユーザーを取得する。
上記の定義を他アクションでも使えるようにする
以下のように、set_user
で呼び出してあげると、同じ記述を書かなくて良いのでまとまった記述になりますよ。
uses_controller
class Public::UsersController < ApplicationController
before_action :authenticate_user!, except: [:show, :rising_users]
before_action :set_user, except: [:edit, :update, :withdraw_input, :withdraw_process, :rising_users]
def show
@latest_post = @user.posts.published.order(created_at: :desc).first
@posts = @user.posts.published.where.not(id: @latest_post&.id).order(created_at: :desc).page(params[:page]).per(10)
@total_views = @user.posts.published.sum(&:impressions_count)
@post_ranking = @user.posts.published.order(impressions_count: :desc).limit(5)
end
def edit
@user = current_user
end
def update
@user = current_user
# if current_user.guest_user?
# flash[:error] = "ゲストユーザーは更新できません。"
# redirect_to request.referer
# else
if @user.update(user_params)
flash[:success] = "ユーザー情報を更新しました。"
redirect_to user_path(@user)
else
render :edit
end
# end
end
def withdraw_input
@user = current_user
end
def withdraw_process
user = current_user
if user.guest_user?
flash[:error] = "ゲストユーザーは退会できません。"
redirect_to request.referer
else
user.update(status: :inactive)
reset_session
redirect_to root_path, notice: "退会しました。"
end
end
def follower_list
@followers = @user.followers
render partial: "follower_list"
end
def following_list
@followings = @user.followings
render partial: "following_list"
end
def liked_posts
@liked_posts = Post.liked_posts(current_user, params[:page], 12)
end
def rising_users
@rising_users = User.calculate_ranking(20)
end
private
def set_user
account_str = params[:account]
sanitized_account_str = account_str.gsub(/[^a-zA-Z0-9_-]/, '')
account_sym = sanitized_account_str.to_sym
@user = User.find_by(account: account_sym)
end
def user_params
params.require(:user).permit(:nickname, :account, :email, :introduction, :icon, :channel)
end
end
まとめ
上記の情報を基に、URLにid以外のカラム(例: nameやaccountなど)を含める方法について学んだ。param
オプションを使用することで、URL内の識別子をカスタムなカラムで置き換えることができる。ただ、このアプローチには注意点もある。
-
一意性の確保
URL内のカスタムカラムの値は一意である必要があるため、ユニーク制約を適切に設定することで、データの整合性を保てる。 -
セキュリティの確保
URL内のカラム値は直接公開されるため、サニタイズが重要。悪意のある入力に対する対策をし、セキュリティリスクを最小限に抑えることが必要。 -
データベースへのアクセス方法に注意
param
オプションを使用すると、通常のid
によるデータベースアクセスができなくなるため、代わりの方法を理解しておく必要がある。カスタムなカラムを使用した検索やバリデーションを実装することが大切。
俺の場合はエラーで苦しんだので、同様のエラーに遭遇した方にとって役立つ情報になることを願っています。
この3日ほど妻が体調を崩してしまい、勉強を中断し息子とずっと一緒に過ごしていました。
ある程度実装には余裕があったので、余裕を持って進めることってとても大事。
妻の体調が戻ってきたのでまた明日から巻き返していこう!
息子がどんどん言葉を覚えてきており、理解力も本当にすごい!1歳6か月ですがコミュニケーションに不自由を全く感じない。
子どもと同じように俺も技術を覚えていきます♪
Discussion