46
36

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のルーティングでid以外の数値カラムをURLに使うときの注意点

Last updated at Posted at 2018-08-13

前提

User
  id:   integer (uniq)
  name: string  (uniq)
  code: integer (uniq)

というモデルに対してshowアクションを作成する際、

通常、 routes.rb

resources :users, only: :show

を書くことで

users/:idなルーティングが作成されますが、
idカラムではなくname(string)やcode(integer)をURLに使用する方法を↓に書きます

name:stringをURLに使いたい場合

まずベーシックなやり方から。

routes.rb

resources :users, only: :show, param: :name

これで users/:nameでアクセスできるようになります。

users_controller.rb

パラメータが:idから:nameにかわるのでコントローラでも対応が必要です。

元がこんなコードなら

def show
  @user = User.find(params[:id])
end

↓こんなかんじに変えます

def show
  @user = User.find_by!(name: params[:name])
end


findはレコードが見つからない場合 ActiveRecord::RecordNotFoundがraiseされますが、
find_byはレコードが見つからない場合 nilが返るだけなので、
例外キャッチして404などを表示するために、 ActiveRecord::RecordNotFoundがraiseされる find_by!を使います

↓find_byとfind_by!の実装

def find_by(arg, *args)
  where(arg, *args).take
rescue ::RangeError
  nil
end

def find_by!(arg, *args)
  where(arg, *args).take!
rescue ::RangeError
  raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
                           @klass.name)
end

user.rb

このままだとlink_to等のヘルパーメソッドでidが使用されるため、モデルで to_paramをオーバーライドします

def to_param
  name
end

(わざわざ説明する必要があるかわかりませんが、わかりやすく書くと)

def to_param
  return self.name
end

と同じです。


以上がid以外のstringのカラムをURLに使用する際の常套手段ですが、
integerのカラムを使用する場合はひと手間増えます。

code:integerをURLに使いたい場合

routes.rb

resources :users, only: :show, param: :code, constraints: { code: /\d+/ }

上の例と違うのは、数値のみを受け付けるconstraintsを足している点です。
これを設定しないと、 users/1hoge等でアクセスしても users/1にルーティングされてしまいます。

原因は調べてないのでしりませんが、
多分内部的にintegerのカラムを検索する際に #to_iをしているはずで、
String#to_iは先頭から数値部分だけを数値に変換するという挙動をするから・・だと思います

'100'.to_i        # => 100
'100hoge000'.to_i # => 100

users_controller.rb

ここは一緒です

def show
  @user = User.find_by!(name: params[:code])
end

user.rb

def to_param
  code.to_s
end

カラムはintegerなので to_sする必要があります。

おわり

constraintsで数値以外を弾くのは結構わすれがちなので、
id以外の数値カラムをURLに使用したい場合はご注意。

46
36
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
46
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?