RailsのURL設計を考えてみる(7) リスト操作
リスト操作といえば昔からActsAsListが定番ですが、「上に移動」「下に移動」のリクエストをどのようなURLで実行していますか?
http://blog.takuyan.com/blog/2013/02/19/consideration-of-how-to-operate-the-list-on-rails/
この話を今週のSendagaya.rbで@kattonさんとしていました。そのときはあまり時間がなく、中途半端な答えしかできなかったのですが、せっかく@kattonさんがわかりやすい形でブログに書いているので、もうちょっと突っ込んで考えてみました。
久しぶりの「URL設計を考えてみる」シリーズ記事も書けたw @kattonさんありがとうございます!
モデルはこのようなものを考えます。
class List < ActiveRecord::Base has_many :items, :order => "position" end class Item < ActiveRecord::Base belongs_to :list acts_as_list :scope => :list end
itemに対する操作
https://github.com/swanandp/acts_as_listMethods That Change Position and Reorder List
list_item.insert_at(2)
list_item.move_lower
will do nothing if the item is the lowest itemlist_item.move_higher
will do nothing if the item is the highest itemlist_item.move_to_bottom
list_item.move_to_top
list_item.remove_from_list
基本的な考え方
HTTPメソッド
操作に対応するHTTPメソッドを考えます。冪等な操作かそうでないかを考えると見分けやすいです。(「冪等(べきとう)」についてはこちらの記事参照)
- insert_at(n) : PUT(追加の場合POSTだが考慮外)
- move_lower : POST
- move_higher : POST
- move_to_bottom : PUT
- move_to_top : PUT
- remove_from_list : DELETE
考え方 その1
例:move_to_top
単純に、位置をさす数値positionをリソースとして使う。
PUT /items/123/position position=0
もしくは
PUT /items/123 item[position]=0
これで insert_at(n) も実現可能。
ただし、move_to_bottomで破綻する(positionの下限がわからないため)。
考え方 その1-1
位置をさすpositionの値に、数値に加えて'bottom'を許す。
PUT /items/123/position position=bottom
あまりきれいではないし、エラーハンドリングなど扱いが面倒になる可能性があるが、だいたいうまくいきそう。
考え方 その1-2
例:move_to_top
topかどうかをさすリソース position_top をつくる。
(フラグの考え方。これもパターンっぽいので、あとで名前つける)
PUT /items/123/position_top position_top=true
ここからmove_to_bottomを考えると、topとbottomは排他的なため、リソースは1つにまとめられる。
PUT /items/123/position_edge position_edge=bottom
topでもbottomでもないときはGETすると'other'や'false'が返される。
ただここまで来ると「その1-1」とあまり変わらなくなっている気も。
考え方 その2
例:move_higher
これはもう、POSTなのでしょうがないw
itemへのPOST
POST /items/123 position=move_higher
positionへのPOST
POST /items/123/position move_higher=1
listの順序リソースordersをPOST(create)
POST /list/1/orders operations[move_higher]=123
いろいろ考えられますが、決定打がない。逆に言うと単純な場合ならどれでも問題ない。(ほんとはできる限り整合性のとれた形でfixしたい)
move_lowerも同様。
雑感
毎回考えるのは不毛だし、routesを書くのも面倒なので、こういうリソース設計も、ある程度パターン化してgemに含まれていればうれしいですよね。
僕が目指しているのはそういう方向です。