66
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Organization

Railsで、URLにIDでなく名前を入力して、アクセスする方法

showやeditなど、member系のアクションに、数値のIDなどではなく、TwitterIDのような一意の文字列でアクセスする方法。

例えば、

http://your.app.com/users/400

でなく

http://your.app.com/users/bob-smith

でアクセスできるようにする。

単純にURLのかっこ良さが上がる気がするし、文字列でのアクセスのみ受け入れるようにしたら、サイトの持っている情報のスクレイピング対策にもなる。

例として、適用するモデル名をUser、urlに使用するカラム名をcanonical_nameとする。ここではidcanonical_nameのどちらでもアクセスできるようにする例を書く。

モデル側のコード

app/models/user.rb
class User < ActiveRecord::Base
  validates :canonical_name,
    uniqueness: { case_sensitive: false },
    format: { with: /^[A-Za-z][\w-]*$/ },
    length: { minimum: 3, maximum: 25 }

  def to_param
    canonical_name ? canonical_name : id.to_s
  end

  def self.find_by_canonical_name_or_id(arg)
    find_by_canonical_name(arg) || find(arg)
  end
end

to_paramというActiveRecordのメソッドが肝。これで通常の表示がidからcanonical_nameに切り替わる。
validationは大体こんな感じにすると良いと思う。ここでは大文字小文字が違うだけのcanonical_nameは許さないようにしているが、そもそも大文字を禁止するのもありだと思う。
なお、ここではcanonical_nameが設定されていないUserもいることを前提としている。

コントローラー側のコード

app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_filter :load_user, only: [:show, :edit, :update, :destroy]
  ## if you use cancan
  # load_and_authorize_resource :user, find_by: 'find_by_canonical_name_or_id'

  private
  def load_user
    @user = User.find_by_canonical_name_or_id(params[:id])
  end
end

数字でなくてもidの情報はparams[:id]に入って渡される。
canonical_nameでしかアクセスできないようにしたい時はload_userUser.find_by_canonical_nameを使えば良い。

別案

探すときに、find_by_canonical_name_or_idというのを使うとto_paramを変更しているクラスだけ、findでModelを探せなくなってしまう。これだと困る場合は、

app/models/user.rb
  def self.find(arg)
    find_by_canonical_name(arg) || super
  end

とfindを上書きしてしまえばいいかもしれない。

追記

https://gist.github.com/agnellvj/1209733 にもっといろんな方法が載っているのを発見。興味ある人は見てみるべし。

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
Sign upLogin
66
Help us understand the problem. What are the problem?