fukajun さんの party tools の shuffleをどうするか考えた
resources :events do
resources :attendances do
collection do
post :shuffled, :action => :shuffle
get :shuffled
end
end
end
resources :users
events <--(n:n)--> users
↓
events <--(1:n)--> attendances <--(n:1)--> users
create_table "attendances", :force => true do |t|
t.string "comment"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id"
t.integer "event_id"
t.integer "position"
end
ここまでが既存の設計。
ポイント:結局、RDBの設計をちゃんとすれば答えは見えてくる!
shuffleの入れ方 その1
attendancesのpositionを生成するという考え方。(Filtered Subresource パターン)
/events/1/attendances/position
とか?
部分集合として、レコードを抽出するというよりも、縦にカラムを抽出するようなイメージ。
ただし、positionを自分で決定してGET, PUTするならこれでよいが、shuffleの場合システム側で決定してほしい。
アルゴリズムリソース(何らかの計算結果のリソース)に近いが、ランダム要素があるためGETするたびに結果が変わってしまうのはまずい。やはりPOST(or PUT)でなければならない。
(これは、たまたま難しい例。GET, PUTだけでうまくいく場合が多い)
この場合、shuffled
というフラグの形で考えるとよい。
/events/1/attendances/shuffled
もしくは
/events/1/shuffled
シャッフルされていないときは、GETするとfalse
が返ってくる。
true
をPUTすることで、シャッフル処理が行われ、positionがセットされる。
shuffleの入れ方 その2
今までは、シャッフルは1回のみという前提。
シャッフルが複数回できて、過去の順番も保存されていて見られるとするならどうするか。
(実際には複数必要なくても、リソース設計する際に考え方として有用)
A. イベントにラウンドが複数あると考える
1つのイベントの中に第1ラウンド、第2ラウンド、…とあるイメージ。それぞれに参加者がいる。
(なので、それぞれに参加者が異なる可能性もある)
events
^
|
(1:n)
|
v
rounds <--(1:n)--> attendances <--(n:1)--> users
/events/1/rounds/2/attendances/shuffled
もしくは
/events/1/rounds/2/shuffled
B. あくまで、positionが複数あると考える
イベントごとの参加者は絶対に同じにしたい場合。
events <--(1:n)--> attendances <--(n:1)--> users
^
|
(1:n)
|
v
orders
この場合 /events/1/attendances/2/orders
などとはできないことに注意。
なぜなら、attendancesは粒度が細かすぎて、その子のordersはほとんど意味を持たない。
/events/1/users
も妥当なので、テーブルは直接つながっていなくてもよい。
/events/1/shuffles/2
?
このURLをどうやって導出するか。