0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails で名前付きルーティングと通常ルーティングを併用したいとき

Posted at

はじめに

Rails の URL で、通常の /hoge/:id のようなルーティングと /hoge/fuga のような名前付きルーティングを併用したいという課題がありました。

その際どのように対応したのかを備忘として残しておきます。

前提環境

  • Rails 5.2.2.1

サンプル例

name カラムのある Post モデルを例にします。

このモデルの name カラムに文字列が入っていれば、id ではなく name の文字列を URL として使うことを想定します。

  • name が空 → /posts/1
  • namehoge と入っている → /posts/hoge

方針

方針としては、Rails ガイド を参考に、以下のように進めました。

  • routes で利用するパラメータ識別子修正
  • ActiveRecord::Base#to_param をオーバーライド
  • 名前付きルーティング・通常ルーティングどちらでもレコードを find できるメソッド作成

対応

routes で利用するパラメータ識別子修正

まず、routes のパラメータ識別子を修正します。param オプションを使うことで可能です。

idname で find したかったので、id_or_name というパラメータ名にしています。

Rails.application.routes.draw do
  # 中略
  resources :posts, param: :id_or_name
  # 中略
end

ActiveRecord::Base#to_param をオーバーライド

次に、ActiveRecord::Base#to_param をオーバーライドします。

name があれば name を、存在しなければそのまま id を利用する形としました。

class Post < ApplicationRecord
  # 中略
  def to_param
    return name if name.presence
    super
  end
end

名前付きルーティング・通常ルーティングどちらでもレコードを find できるメソッド作成

最後に、Post モデルに名前付きルーティング・通常ルーティングどちらでもレコードを find できるメソッドを追加します。

idname でレコードを検索し、どちらかがマッチしていればそのレコードを返却します。
存在しない場合は一応 ActiveRecord::RecordNotFound で例外処理しています。

class Post < ApplicationRecord
  # 中略
  def self.find_by_id_or_name(id_or_name)
    if object = self.where(id: id_or_name).or(self.where(slug: id_or_name)).first
      object
    else
      raise ActiveRecord::RecordNotFound
    end
  end
end

利用するときは以下のようなメソッドの呼び出し方となります。

Post.find_by_id_or_name(params[:id_or_name])

終わりに

name 重複する場合など、考慮する点はまだあるかも知れませんが、一旦こちらで対応はできました。

もっと良いやり方などありましたらコメントいただけるとありがたいです!

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?