【Rails】5分でacts_as_lists実装する方法

# はじめに

Railsアプリケーションは爆速で開発できるところがメリットですので、開発スピードに着目して記事を書きました。
5分で acts_as_list の検証ができるように、vim だけでも書けるようにファイルパスを全てしましたので、
vimを使ってパスをコピー＆ペーストして、ファイル内のコードを変更することができます。

プロトタイプを作る時などにスピード重視で作る事は開発にとって重要な事だと思いますので、ぜひご活用ください。

# コマンド

```bash
# Rails アプリケーション作成
$ rails _5.2.4.2_ new five_min_actsaslist
$ cd five_min_actsaslist

# scaffold でモデルを作成
$ rails g scaffold user name:string
$ rails g scaffold post title:string user_id:integer position:integer
$ rails db:migrate RAILS_ENV=development

# テストデータを入力しておきます
$ rails c
> user = User.create(name: 'Suzuki')
> Post.create(title: 'test_1', user_id: user.id, position: 1)
> Post.create(title: 'test_2', user_id: user.id, position: 2)
> Post.create(title: 'test_3', user_id: user.id, position: 3)
> Post.create(title: 'test_4', user_id: user.id, position: 4)
> Post.create(title: 'test_5', user_id: user.id, position: 5)
> exit
```

# Gemfile

Gemfile へ gem を追加して```bundle install```

```ruby:Gemfile
gem 'acts_as_list'
```

```bash
$ bundle install
```

# Model

モデルは、```Post```モデルを持つ```User```の構成を作成します。

```ruby:app/models/user.rb
class User < ApplicationRecord
  has_many :post, -> { order(:position) }
end
```

```ruby:app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
  acts_as_list scope: :user
end
```

# route.rb

```scaffold``` で ```routes.rb``` の中身が作成されていますが、全て削除して以下で書き換えてください。

```ruby:config/routes.rb
Rails.application.routes.draw do
  resources :users do
    resources :posts do
      member do
        get :higher
        get :lower
        get :top
        get :bottom
      end
    end
  end
end
```

# Controller

まずは、```index```の中身を書き換えてください。
次に、```higher```、```lower```、```top```、```bottom```メソッド を追加してください。

```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController

  def index
    @user = User.find(params[:user_id])
    @posts = Post.where(user_id: params[:user_id]).order(:position)
  end

  # 省略

  def higher
    Post.find(params[:id]).move_higher
    redirect_to action: :index
  end

  def lower
    Post.find(params[:id]).move_lower
    redirect_to action: :index
  end

  def top
    Post.find(params[:id]).move_to_top
    redirect_to action: :index
  end

  def bottom
    Post.find(params[:id]).move_to_bottom
    redirect_to action: :index
  end

  # 省略
end
```


# HTML

```scaffold``` で HTML も作成されていますので、"以下を追加"と書かれているところから追記してください。

```erb:app/views/posts/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Posts</h1>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Position</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td><%= post.position %></td>

        <!-- 以下を追加 -->
        <td><%= link_to "↑↑↑", top_user_post_path(@user.id, post) %></td>
        <td><%= link_to "↑", higher_user_post_path(@user.id, post) %></td>
        <td><%= link_to "↓", lower_user_post_path(@user.id, post) %></td>
        <td><%= link_to "↓↓↓", bottom_user_post_path(@user.id, post) %></td>
        <!-- ここまで-->

        <td><%= link_to 'Show', post %></td>
        <td><%= link_to 'Edit', edit_post_path(post) %></td>
        <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Post', new_post_path %>
```

# 開発環境で表示してみる

```bash
$ rails s
```

次のURLへアクセス。localhost:3000/users/1/posts

"↑" や　"↓" ボタンを押して順番が入れ替わることを確認してみてください。

# まとめ

今回は ```acts_as_list``` の同期処理について記事を書きました。
本来はドラッグ&ドロップで順番を変更したいという需要があるかと思いますので、気が向いたらその記事も書きたいなと思います。


# 参考
* GitHub ( brendon / acts_as_list )
    * https://github.com/brendon/acts_as_list
* 【Rails】acts_as_listを使った並べ替え機能を同期/非同期それぞれで実装
    * https://qiita.com/d0ne1s/items/0e07d4966cad4bd22908

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/