Railsでモデルの並び順を維持するためのプラグインacts_as_listについて。
ドラッグアンドドロップでの並び替えも(頑張れば?)できるらしい!
確認は Rails 2.3.4 で行いました。
こちらを参考にしました→つくるぶガイドブログ: ドラッグアンドドロップで並べ替え(Rails + Ajax)
とりあえず、画面遷移有り(非AJAXで)で順番変更するところまでやってます。ドラッグアンドドロップはあとで…。
githubからインストールします。
ruby script/plugin install git://github.com/rails/acts_as_list.git
※これ自身は古く、派生がいくつかあるみたいですが、ここではとりあえずは本家を入れてみます
Projectがあり、Projectがhas_many(1対多)で持っているTaskを順番に並べたいとします。
まずは、Projectモデルのhas_many :tasksに order => :position を追加します。
app/models/project.rb:
1 2 3 4 | class Project < ActiveRecord::Base : has_many :tasks, :order => :position end |
次に、Taskモデルで、Projectごとに並び順を設定するように、
acts_as_list :scope => :project を記述します。
app/models/task.rb:
1 2 3 4 5 6 7 8 | class Task < ActiveRecord::Base : # projectと1対1で関連付け belongs_to :project # 並び順は project ごとに設定 acts_as_list :scope => :project : end |
has_manyされるTaskにpositionカラム(ただし、integer)を追加します。
$ ruby script/generate migration add_position_to_tasks position:integer exists db/migrate create db/migrate/20090908100212_add_position_to_tasks.rb
以下が自動生成されます。(※Railsのバージョンによっては自動では生成されない)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class AddPositionToTasks < ActiveRecord::Migration def self.up add_column :tasks, :position, :integer # 既存のテーブル要素に順番付け Task.all.each do |q| q.send :add_to_list_bottom q.save! end end def self.down remove_column :tasks, :position end end |
上記の q.send :add_to_list_bottomでは、既存のテーブルの項目のpositionがそのままだとnullで動作しないため初期値を入れるようにしてます。ここではid順に番号をふります。
なお、新規に項目を生成した場合(Task.new,Task.createとか)は自動でpositionの値が振られます。
また、ActiveRecord::Acts::List::InstanceMethods.add_to_list_bottomがprivateメソッドなため、sendを使ってよんでいます。
migrateします。
$ rake db:migrate (in /mnt/c/my_project/trunk) == AddPositionToTasks: migrating ============================== -- add_column(:tasks, :position, :integer) -> 0.0400s == AddPositionToTasks: migrated (0.0400s) ===================== $ rake db:migrate:redo # 念のためredo == AddPositionToTasks: reverting ========================== -- remove_column(:tasks, :position) -> 0.0200s == AddPositionToTasks: reverted (0.0200s) ================= == AddPositionToTasks: migrating ========================== -- add_column(:tasks, :position, :integer) -> 0.0100s == AddPositionToTasks: migrated (0.0100s) =================
※横幅の都合で==を少しはしょってます
まずは、コントローラーを修正してTaskのリスト内で上下移動できるようにしてみましょう。
これができれば、他にも応用が効きます。
app/controllers/task_controller.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | def index # position順にソートしてリスト表示する @questions = Question.all(:order => :position) : end : # 順番を上に移動 def move_order_higher move_order(:move_higher) end # 順番を下に移動 def move_order_lower move_order(:move_lower) end # 順番を最上位に移動 def move_order_to_top move_order(:move_to_top) end # 順番を最下位に移動 def move_order_to_bottom move_order(:move_to_bottom) end private def move_order(method) Task.find(params[:id]).send method flash[:notice] = 'タスクを並びかえました。' respond_to do |format| format.html { redirect_to :action => 'index' } format.xml { head :ok } end end |
app/views/index.html.rb:
1 2 3 4 5 6 7 8 9 10 11 | : <td><%= task.first? ? '': link_to('▲▲', :action => :move_order_to_top, :id => task) %> <td><%= task.first? ? '': link_to('▲', :action => :move_order_higher, :id => task) %> <td><%= task.last? ? '': link_to('▼', :action => :move_order_lower, :id => task) %> <td><%= task.last? ? '': link_to('▼▼', :action => :move_order_to_bottom, :id => task) %> </tr> <% end %> |
これで準備はOKヽ( ´ー`)ノ
http://localhost:3000/tasks/ を開き、リスト右の▲や▼で並び替えられるか確認してください。
うまく行きました?
[TODO]:acts_as_listでドラッグアンドドロップする方法について書く
Show recent 10 comments. Go to the comment page.