Assets.github.com%2fimages%2fgravatars%2fgravatar-140

Rails等でURLにランダムな文字列を使いたい時のアレ Edit

  • cutmail
  • lunchub
  • fakestarbaby
  • sakisaka7
  • shtakai@github
  • sue738
  • yoshifumi0521@github
  • tak01cuebs
  • Darmuck
  • nekogeruge_987
  • hayori@github
  • noromanba@github
  • rnurakami@github
  • matsumos@github
  • uranoa
  • semind
  • nicklegr
  • mryreplicant
  • ongaeshi
  • pasela
Edit

http://example.com/samples/lk23Affa

みたいなURLにランダムな文字列を使いたい時ありますよね。
上記がRailsのActiveResourceのRESTfulっぽいルーティングだとしたら、
samplesというresourceのid=lk23Affaにアクセスしてることになりますね。

ActiveRecordだと普通にテーブルを作成していったら、
主キーのidは、auto_incrementのただの数字連番になってしまいます。
また、文字列の主キーを設定するのが結構面倒なので *1、
access_tokenというようなカラムで別に値を保持しておくのがよさそうです。

db/migrate/xxx_create_samples.rb
class CreateSamples < ActiveRecord::Migration
  def change
    create_table :samples do |t|
      t.string :access_token, :null => false, :limit => 6
      t.timestamps
    end
    add_index :samples, :access_token, :unique => true
  end
end
app/model/sample.rb
class Sample < ActiveRecord::Base
  validates_uniqueness_of :access_token
  validates_presence_of :access_token
  after_initialize :set_access_token

  private
  def set_access_token
    self.access_token = self.access_token.blank? ? generate_access_token : self.access_token
  end                                                                                                                                                                                          

  def generate_access_token
    tmp_token = SecureRandom.urlsafe_base64(6)
    self.class.where(:access_token => tmp_token).blank? ? tmp_token : generate_access_token
  end
end
config/routes.rb
  get '/samples/:access_token' => 'samples#show'
app/controller/samples_controller.rb
class SamplesController < ActionController::Base
  def  show
    @sample = Sample.where(:access_token => params[:access_token]).first
  end
end

こんな感じに書いたらユニークな文字列をURLに含めて、
リソースを表示させることが出来るかと思います!
とりあえず、access_tokenって名づけましたが、もっと一般的に使われてる良い名前があったら教えて欲しいです。

追記:2012.01.02
@tkawa さんの作った https://github.com/tkawa/resources_id_replace
を使うと、綺麗にRoutingが出来るようになるようです。
詳しくは↓のコメント欄をどうぞ。

*1: MySQLでは、migrationファイル中にexecuteメソッドを使ってSQLを直に書き、alter tableでprimary keyを追加できるけど、sqlite3では、alter tableこそ使えるものの、primary keyを追加できないという問題あり。

参考ページ:
- URL短縮サービスで使われるような、ランダムでユニークなアクセストークンを発行するプラグイン - 篳篥日記
- ActiveRecord で id 以外のカラムをプライマリキーにして、しかも型が int じゃないときの話 - 何かの記録
- SQLite Query Language: ALTER TABLE



config/routes.rb
get '/samples/:access_token' => 'samples#show'

だとURLの生成とか少し困りそうなので、

config/routes.rb
resources :samples

にしたいんですけど、params[:id]に入ってしまうのが微妙ですよね。

そこで

config/routes.rb
resources :samples, :replace_id_with => 'access_token'

と書くと

    samples GET    /samples(.:format)                    samples#index
            POST   /samples(.:format)                    samples#create
 new_sample GET    /samples/new(.:format)                samples#new
edit_sample GET    /samples/:access_token/edit(.:format) samples#edit
     sample GET    /samples/:access_token(.:format)      samples#show
            PUT    /samples/:access_token(.:format)      samples#update
            DELETE /samples/:access_token(.:format)      samples#destroy

になるgemを作ってみたんですけど、どうでしょうか。

https://github.com/tkawa/resources_id_replace

@tkawa-san
良いですね!!使えそうです!!
今作ってるものは、Padrinoで作ってたので、ActiveRecord周りしか
調べてなかったのですが、Rails使うならそのgemが便利そうですね。
今度試してみます。

Sign up and follow ainame :)

Sign up with GitHub/Twitter

x close