11
14

More than 3 years have passed since last update.

【Rails】ドラッグ&ドロップ機能の実装(エフェクト付き)

Last updated at Posted at 2020-06-12

目標

ezgif.com-video-to-gif.gif

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

Slim導入
Bootstrap3導入
投稿機能実装

実装

1.Gemを導入

Gemfile
# 追記
gem 'jquery-ui-rails'
gem 'ranked-model'

jquery-ui-rails
➡︎ jQuery UIを使用出来るようにする。

gem 'ranked-model'
➡︎ Bookの並び順を管理出来るようにする。

3.カラムを追加

ターミナル
$ rails g migration AddRowOrderToBooks row_order:integer
ターミナル
$ bundle
schema.rb
create_table "books", force: :cascade do |t|
  t.integer "user_id"
  t.string "title"
  t.text "body"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.integer "row_order"
end

4.モデルを編集

Bookモデルでranked-modelを使えるようにする。

book.rb
# 追記
include RankedModel
ranks :row_order

5.コントローラーを編集

indexアクションを編集

books_controller.rb
# 変更前
@books = Book.all

# 変更後
@books = Book.rank(:row_order)

②ストロングパラメーターにrow_order_positionを追加する。

カラム名はrow_orderだが、ここではGemの使用上row_order_positionと記述する。

books_controller.rb
def book_params
  params.require(:book).permit(:title, :body, :row_order_position)
end

sortアクションを追加

books_controller.rb
def sort
  book = Book.find(params[:book_id])
  book.update(book_params)
  render body: nil
end

render body: nil
➡︎ アクションだけを実行し、ビューは呼び出さない。

6.ルーティングを編集

route.rb
# 変更前
resources :books

# 変更後
resources :books do
  put :sort
end

7.ビューを編集

books/index.html.slim
/ 「table-sortable」というクラスを付与
table.table.table-bordered.table-sortable
  thead
    tr
      th
        | 投稿者
      th
        | タイトル
      th
        | 本文
      th

  tbody
    - @books.each do |book|
      / trタグにクラスを付与し、データを設定する
      tr.item(data = { model_name: book.class.name.underscore, update_url: book_sort_path(book) })
        td
          = link_to book.user  do
            = book.user.name
        td
          = link_to book.title, book_path(book)
        td
          = book.body
        td
          -if book.user == current_user
            = link_to '削除', book, method: :delete, data: { confirm: '本当に削除してもよろしいですか?' }, class: 'btn-sm btn-danger'

model_name: book.class.name.underscore
➡︎ 「book」はeach分のブロック変数にあたる。

8.application.jsを編集

application.js
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery
//= require jquery-ui/widgets/sortable // 追記
//= require jquery-ui/effects/effect-highlight // 追記
//= require bootstrap-sprockets
//= require_tree .

//= require jquery-ui/widgets/sortable
➡︎ jQuery UIを有効化

//= require jquery-ui/effects/effect-highlight
➡︎ ドラッグ&ドロップ時のエフェクトを有効化

9.JavaScriptファイルを作成・編集

ターミナル
$ touch app/assets/javascripts/table_sort.js
table_sort.js
$(function(){
  $('.table-sortable').sortable({
    axis: 'y',
    items: '.item',

    // Ajaxで並び順のデータをコントローラーに送信
    update(e, ui) {
      let item = ui.item;
      let item_data = item.data();
      let params = { _method: 'put' };
      params[item_data.model_name] = { row_order_position: item.index() };
      $.ajax({
        type: 'POST',
        url: item_data.update_url,
        dataType: 'json',
        data: params,
      });
    },

    // ドラッグ幅をテーブルに合わせる
    start(e, ui) {
      let cells, tableWidth, widthForEachCell;
      tableWidth = $(this).width();
      cells = ui.item.children('td');
      widthForEachCell = tableWidth / cells.length + 'px';
      return cells.css('width', widthForEachCell);
    },

    // エフェクトを付与
    stop(e, ui) {
      return ui.item.children('td').effect('highlight');
    },
  });
});

10.カーソルのデザインを変更

application.scss
// 追記
.table-sortable {
  tr.item {
    cursor: row-resize;
  }
}
11
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
14