Help us understand the problem. What is going on with this article?

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

はじめに

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 重複する場合など、考慮する点はまだあるかも知れませんが、一旦こちらで対応はできました。

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

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした