railsがんばる子

Ruby on Railsがんばる子です。胡蝶蘭のECサイトを運営しています。

RankedModelをSTIで使う時にハマった

Rails 4で作るドラッグアンドドロップで表示順を変更できるサンプルアプリ(スクリーンキャスト付き)などで有名なRankedModel。 RankedModelを知ってから、順序を指定するようなモデルではRankedModelを利用しています。

本日はRankedModelをSTIを利用したとき、順番が意図した通りにならずハマったので共有します。

何が起きたのか?

RankedModelでは作成した順番に並ぶようにデータが作成されていきますが、STIを利用したときに上手く行きませんでした。 下の例では、car1、car2、truck1、truck2と並んで欲しいところです。 どうやらモデルごとに値を決めているようです。

class Vehicle < ActiveRecord::Base
  ranks :row_order
end

class Car < Vehicle
end

class Truck < Vehicle
end

Car.create!(name: :car1)
Car.create!(name: :car2)
Truck.create!(name: :truck1)
Truck.create!(name: :truck2)


Vehicle.rank(:row_order).pluck(:name)
#=> ["car1", "truck1", "car2", "truck2"] ( ゚∋゚)

解決策

ranksメソッドの第二引数にオプションとしてclass_nameを渡せば解決します。

よく見たらGithubに書いてありました。

class Vehicle < ActiveRecord::Base
  ranks :row_order, class_name: 'Vehicle'
end

class Car < Vehicle
end

class Truck < Vehicle
end

Car.create!(name: :car1)
Car.create!(name: :car2)
Truck.create!(name: :truck1)
Truck.create!(name: :truck2)


Vehicle.rank(:row_order).pluck(:name)
#=> ["car1", "car2", "truck1", "truck2"]

解決策に至るまでに考えたこと

  • データを投入したあとにupdate_columnで値を更新する
Car.create!(name: :car1)
Car.create!(name: :car2)
Truck.create!(name: :truck1)
Truck.create!(name: :truck2)
Vehicle.rank(:row_order).each.with_index { |v, i| v.update_column(:row_order, i + 1) }
# => rankした時点でcar1、truck1、car2、truck2の順番に並ぶため、無意味。この時点ではモデルごとに値を決めていることに気づいていなかった