- お知らせ -
  • 当wikiのプログラムコードの表示を直してみました(ついでに長い行があると全体が下にぶっ飛ぶのも修正)。不具合があればBBSまでご連絡下さい。

Ruby/Ruby on Rails

はじめに Edit

Railsでモデルの並び順を維持するためのプラグインacts_as_listについて。

ドラッグアンドドロップでの並び替えも(頑張れば?)できるらしい!

確認は Rails 2.3.4 で行いました。

こちらを参考にしました→つくるぶガイドブログ: ドラッグアンドドロップで並べ替え(Rails + Ajax)

とりあえず、画面遷移有り(非AJAXで)で順番変更するところまでやってます。ドラッグアンドドロップはあとで…。

メニュー Edit

インストール Edit

githubからインストールします。

ruby script/plugin install git://github.com/rails/acts_as_list.git

※これ自身は古く、派生がいくつかあるみたいですが、ここではとりあえずは本家を入れてみます

前提条件 Edit

Projectがあり、Projectがhas_many(1対多)で持っているTaskを順番に並べたいとします。

モデルを修正 Edit

まずは、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) =================

※横幅の都合で==を少しはしょってます

コントローラーとビューの修正 Edit

まずは、コントローラーを修正して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でドラッグアンドドロップする方法について書く

参考リンク Edit


Show recent 10 comments. Go to the comment page.

  • migrationの修正と、indexのorderを調整したらうまく行きましたので修正。 -- TOBY 2009-09-09 (Wed) 20:21:51
  • 最下位、最上位に移動するメソッドもコントローラーとビューに追加。それにともない若干DRYした。 -- TOBY 2009-09-10 (Thu) 20:02:35
Name:

Front page   Edit Freeze Diff Backup Upload Copy Rename Reload   New Pages Search Recent changes   Help   RSS of recent changes
Last-modified: 2010-06-02 Wed 20:35:24 JST (2753d)