最近つくったgem resources_id_replace & bootstrap-editable-rails

最近、Railsのgem(プラグイン)をよくつくっています。そのことについて、たまにツイートぐらいしかしていないので、ちゃんと紹介しようと思って書いてみます。使ってもらえればうれしいです。
(ブログさぼりすぎ…)

resources_id_replace

これは何?

resources で /users/1 というURLのidの代わりに、名前を使って /users/tkawa などとしたいときがあります。
コード上は特に変更しなくても、 params[:id] に 'tkawa' が入ってくるのでそのまま処理はできるのですが、名前がidなのに中身がidじゃないので

@user = User.find_by_name!(params[:id])

のようになってしまいます。これは気持ち悪い。でも resources では :id の部分が変えられないんですよね。うーむ。
これを変更できるようにするgemです。

resources で :replace_id_with オプションが使えるようになります。

resources :users, :replace_id_with => 'name'

生成されるルーティングはこのようになります。

    users GET    /users(.:format)            users#index
          POST   /users(.:format)            users#create
 new_user GET    /users/new(.:format)        users#new
edit_user GET    /users/:name/edit(.:format) users#edit
     user GET    /users/:name(.:format)      users#show
          PUT    /users/:name(.:format)      users#update
          DELETE /users/:name(.:format)      users#destroy

無事、このように自然に書けるようになりました!

class UsersController < ApplicationController
  def show
    @user = User.find_by_name!(params[:name])
  end
end


あとは、url_forなどURL生成メソッドの対応のため to_param をオーバーライドしておくのがいいですね。

class User < ActiveRecord::Base
  def to_param
    name
  end
end


FriendlyId との違い

同じ /users/tkawa のようなURLを実現するために FriendlyId というgemがあります。

使ったことはないので、以下間違っていたらすみません。
FriendlyIdはかなり内部に手を入れていて、User.find(params[:id])のままで、 params[:id] が 'tkawa' でもOKなように拡張します。いわば「id自体を変える」というイメージです。
しかし、実際の user.id は数字のままなはずです。もちろんDBも。そのへんがわかりにくくなることもありそうです。(ほかにもhistoryとかいろいろ機能があるので楽ではあります)

resources_id_replace は、ソースを見てもらえばわかりますが、複雑なことは全くしていません。 resources で“id”とハードコードされている部分を変えられるようにしただけです。なので params[:id] ならidの数値、 params[:name] ならnameの文字列、という一貫性が保てます。

追記:Rails 4には同様の機能が実装されているので、このgemは不要になりました。
Rails 4では、resourcesにparamというオプションを使うことができ、これで:idに代わる名前を指定できます。

resources :users, param: :name

bootstrap-editable-rails

これは何?

X-editableというJavaScriptのライブラリがあります。テキストをその場で編集できる「インラインエディタ」とか「インプレイスエディタ」とか言われているもので、Twitter Bootstrapの見た目に合わせて作られています(Bootstrapじゃないのもある)。

機能も豊富なので、一度デモを見てみてください。

これをRailsで使おうと思ったのですが、Ajaxで送られるパラメータの仕様が全くRails的ではない…。
そのままでは使えないので、元のソースを書き換えずに、中の動作だけを変更してパラメータの仕様をRailsにあわせるgemです。

HTMLはこのように書きます(実際はerbやhamlで書くでしょう)。

<a href="#" id="username" data-type="text" data-resource="post" data-name="username" data-url="/posts/1" data-original-title="Enter username">superuser</a>

この要素を編集すると、 data-resource と data-name からパラメータが組み立てられ、

PUT /posts/1
Accept: application/json

post[username]=superuser

のようなAjaxリクエストが発行されます。
Railsのコントローラ側では、updateアクションで更新処理をして、ステータス2xxを返せば成功です。

既知の問題

X-editableは内部で jQuery.ajax() メソッドを使っているのですが、jQuery 1.9.0で仕様が変わり、 dataType: json を指定したときにレスポンスボディが空だと、不正なJSONとみなして失敗するようになりました。
これにより、成功時に 204 No Content を返すことができません。
これはjQueryのバグで、すでに修正されているので次のjQueryのリリースでは正常になるはずですが、それまでは何らかの回避策を講じる必要があります。

  • ステータス204を使わず、200 OKでレスポンスボディを返す
  • dataType: null を設定する(ただし、デフォルトでJSONを返すようにする必要があります)
  • jquery-rails 2.2.0 を使わず 2.1.4 を使用する

次回予告(?)

ということで今、もう1つgemをつくっています。GitHubに途中のものはあるのですが、こんなことができます。

Rails 4 で strong parameters を使うようになって、クエリパラメータで絞りこみたい、というときの定番gemにしたいと思っています。詳しくはまたこんど。