taikinakano
@taikinakano (taiki nakano)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

ドラックアンドドロップ機能実装

解決したいこと

ドラックアンドドロップ機能において画面更新時に順番が保存されない

Ruby on Railsでお気に入りの店舗を登録することのできるWebアプリをつくっています。
ドラックアンドロップで要素を動かすことはできるのですが、画面を更新すると順番が保存されていませんでした。ドラックアンドドロップ機能はshopのindexに表示させています。以下の記事を参考に作成しました。
https://qiita.com/fumikao/items/77ffdffc24a9a814fad7
解決方法を教えて下さい。
以下は、検証ツールで発生しているエラーです

発生している問題・エラー

Failed to load resource: the server responded with a status of 422 ()

該当するソースコード

table.sort.js

$(function(){
  $('.table-sortable').sortable({
    update: function(e, ui){
      let item = ui.item;
      let item_data = item.data();
      let params = {_method: 'put'};
      params[item_data.modelName] = { row_order_position: item.index() }
      $.ajax({
        type: 'POST',
        url: item_data.updateUrl,
        dataType: 'json',
        data: params
      });
    },
    stop: function(e, ui){
      ui.item.children('td').not('.item__status').effect('highlight', { color: "#FFFFCC" }, 500)
    }
  });
});

shops_controller

  def index
    @shops = Shop.page(params[:page]).rank(:row_order)
  end

routes.rb

  def index
    @shops = Shop.page(params[:page]).rank(:row_order)
  end


  private
  def shop_params
    params.require(:shop).permit(:shop_name, :image, :address, :comment, :user_id, :row_order_position)
  end

application.js

//= require jquery
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .
//= require jquery-ui/widgets/sortable
//= require jquery-ui/effects/effect-highlight
//= require moment
//= require fullcalendar
//= require bootstrap-sprockets

index.html.erb

     <table class="table">
      <thead class="thead-dark">
      <tr>
      <th>店舗画像</th>
      <th>店舗名</th>
      <th>住所</th>
      </tr>
     </thead>
     <tbody class="bg-light table-sortable">
       <% @shops.each do |shop| %>
       <tr>
        <%= content_tag "tr", class: "item", data: { model_name: shop.class.name.underscore, update_url: shop_sort_path(shop)} do %>
         <td>
         <%= link_to shop_path(shop.id) do %>
         <%= attachment_image_tag shop, :image, size: '200x150', formate: 'jpg', fallback: "no_iamge.jpg" %>
         <% end %>
         </td>
         <td class="pt-4">
           <%= link_to shop_path(shop.id) do %>
           <%= shop.shop_name %>
           <% end %>
          </td>
          <td class="pt-4"><%= shop.address %></td>
       </tr>
       <% end %>
       <% end %>
       <%= paginate @shops %>
     </tbody>
    </table>

schema.rb

  create_table "shops", force: :cascade do |t|
    t.string "shop_name", null: false
    t.string "image_id", null: false
    t.string "address", null: false
    t.text "comment", null: false
    t.datetime "created_at", null: false
    t.integer "user_id"
    t.datetime "updated_at"
    t.string "conversion_shop_name"
    t.string "conversion_address"
    t.integer "row_order"
  end

shop.rb

class Shop < ApplicationRecord
  include RankedModel #ドラックアンドドロップ
  ranks :row_order, with_same: :user_id


  belongs_to :user
  has_many   :products,      dependent: :destroy
  has_many   :genres,        dependent: :destroy
  has_many   :favorites,     dependent: :destroy
  has_many   :bookmarks,     dependent: :destroy
  has_many   :shop_comments, dependent: :destroy
    has_many :notifications, dependent: :destroy
  attachment :image

  validates  :shop_name,     presence: true
  validates  :address,       presence: true
  validates  :comment,       presence: true

  def bookmarked_by?(user)
    bookmarks.where(user_id: user).exists?
  end

  def favorited_by?(user)
    favorites.where(user_id: user.id).exists?
  end

  def self.search_for(content, method)
      Shop.where('conversion_shop_name LIKE ?', '%'+content+'%')
  end

  def self.searched_for(content, method)
      Shop.where('address LIKE ?', '%'+content+'%')
  end

  def self.sort(selection) #いいね順並び替え
    case selection
    when 'new'
      return all.order(created_at: :DESC)
    when 'old'
      return all.order(created_at: :ASC)
    when 'likes'
      return find(Favorite.group(:shop_id).order(Arel.sql('count(shop_id) desc')).pluck(:shop_id))
    when 'dislikes'
      return find(Favorite.group(:shop_id).order(Arel.sql('count(shop_id) asc')).pluck(:shop_id))
    end
  end

  def create_notification_favorite!(current_user)#通知機能の記述
    # すでに「いいね」されているか検索
    temp = Notification.where(["visitor_id = ? and visited_id = ? and shop_id = ? and action = ? ", current_user.id, user_id, id, 'favorite'])
    # いいねされていない場合のみ、通知レコードを作成
    if temp.blank?
      notification = current_user.active_notifications.new(
        shop_id: id,
        visited_id: user_id,
        action: 'favorite'
      )
      # 自分の投稿に対するいいねの場合は、通知済みとする
      if notification.visitor_id == notification.visited_id
        notification.checked = true
      end
      notification.save if notification.valid?
    end
  end

  def create_notification_comment!(current_user, shop_comment_id)
    # 自分以外にコメントしている人をすべて取得し、全員に通知を送る
    temp_ids = ShopComment.select(:user_id).where(shop_id: id).where.not(user_id: current_user.id).distinct
    temp_ids.each do |temp_id|
      save_notification_comment!(current_user, shop_comment_id, temp_id['user_id'])
    end
    # まだ誰もコメントしていない場合は、投稿者に通知を送る
    save_notification_comment!(current_user, shop_comment_id, user_id) if temp_ids.blank?
  end

  def save_notification_comment!(current_user, shop_comment_id, visited_id)
    # コメントは複数回することが考えられるため、1つの投稿に複数回通知する
    notification = current_user.active_notifications.new(
      shop_id: id,
      shop_comment_id: shop_comment_id,
      visited_id: visited_id,
      action: 'shop_comment'
    )
    # 自分の投稿に対するコメントの場合は、通知済みとする
    if notification.visitor_id == notification.visited_id
      notification.checked = true
    end
    notification.save if notification.valid?
  end
end

自分で試したこと

ターボリンクスを無効化することでうまくいくというような記事を見つけたので現在実行しているのですが、ターボリンクスを無効化するとドラックアンドドロップが動かなくなったりするのでうまくいきません。
https://qiita.com/d0ne1s/items/5a4122d2972be3812986

0

1Answer

現状では情報が過多なのでなんとも申し上げられませんが…
エラーメッセージから推察すると
HTTPのレスポンスステータスコードが422なので恐らくサーバ側まで処理は来ていますね。

参考にされた記事は
Rails 5.2.3
jQuery 3.4.1
gemはranked-modelを利用

とのことですが、@taikinakanoさんの開発環境はどのような状態なのですか?
(Railsバージョン詳細 + Gemfile、Gemfile.lockの内容、等々)

###自分で試したこと
ターボリンクスを無効化することでうまくいくというような記事を見つけたので現在実行しているのですが、ターボリンクスを無効化するとドラックアンドドロップが動かなくなったりするのでうまくいきません。

についてですが、
「Turbolinks」はザックリ言うと、基本的に
「<a>タグや「戻る」ボタンでの画面読み込みの際に再利用できる要素は再利用する」という
モノなので今回のエラーコードからすると恐らく関係ないかと予想されます。
(詳しい動作は「fetchReplacement[ajax化]」や「fetchHistory[イベント書換]」で調べてみてください)

0Like

Your answer might help someone💌