Class: Spree::Assets::PositionNormalizer

Inherits:
Object
  • Object
show all
Defined in:
app/services/spree/assets/position_normalizer.rb

Overview

同一 viewable に属する Spree::Asset の position を、現在の並び順 (position, id) を 保ったまま 1..N の連番へ詰め直す。

管理画面の並び替え (stimulus-sortable) は、移動した 1 件だけに asset[position] = 画面上のインデックス + 1 を送る。受け側の acts_as_list は 送られた position が既存レコードと衝突したときにしか周囲を詰め直さないため、 position が 1..N の連番でないと 200 を返すのに並び順が変わらない。 並び替えの直前と、position が壊れうる経路の直後にこのサービスを呼ぶ。

Constant Summary collapse

BROKEN_SCOPE_CONDITION =

position が 1..N の連番になっていない viewable を検出する条件。 欠番 (最小が 1 でない / 最大が件数と一致しない) と重複 (distinct 数が件数と一致しない) を見る。

<<~SQL.squish.freeze
  MIN(position) <> 1
  OR MAX(position) <> COUNT(*)
  OR COUNT(DISTINCT position) <> COUNT(*)
SQL

Class Method Summary collapse

Class Method Details

.broken_scopesArray<Array(String, Integer)>

position が壊れている viewable の一覧。

Returns:

  • (Array<Array(String, Integer)>)

    [viewable_type, viewable_id] の配列



44
45
46
47
48
49
50
# File 'app/services/spree/assets/position_normalizer.rb', line 44

def broken_scopes
  Spree::Asset.unscoped
              .where.not(viewable_id: nil)
              .group(:viewable_type, :viewable_id)
              .having(BROKEN_SCOPE_CONDITION)
              .pluck(:viewable_type, :viewable_id)
end

.call(viewable_type:, viewable_id:) ⇒ Boolean

Returns 詰め直しを行った場合 true、もともと連番だった場合 false.

Parameters:

  • viewable_type (String)
  • viewable_id (Integer)

Returns:

  • (Boolean)

    詰め直しを行った場合 true、もともと連番だった場合 false



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'app/services/spree/assets/position_normalizer.rb', line 26

def call(viewable_type:, viewable_id:)
  return false if viewable_type.blank? || viewable_id.blank?

  assets = ordered_assets(viewable_type, viewable_id)
  return false if sequential?(assets)

  # 1 件ずつ書き換える途中では position が一時的に重複しうるため、
  # 中断や並行読み取りに晒さないようトランザクションでまとめる。
  Spree::Asset.transaction do
    assets.each_with_index do |asset, index|
      asset.update_column(:position, index + 1) unless asset.position == index + 1
    end
  end
  true
end