ruby-on-railsacts-as-list

Is there a way to use acts_as_list with a single parent but many different children?


I've stumbled upon this Rails - acts_as_list with multiple Models. I'm having a hard time understanding how to fit the solution into my current use case.

In my app, I have a section. The section can hold many places, checklists, and notes.

class Section < ApplicationRecord
  has_many :places, -> { order(position: :asc) }, dependent: :destroy
  has_many :notes, -> { order(position: :asc) }, dependent: :destroy
  has_many :checklists, -> { order(position: :asc) }, dependent: :destroy
end

class Note < ApplicationRecord
  acts_as_list scope: :section

  belongs_to :section
end

class Place < ApplicationRecord
  acts_as_list scope: :section

  belongs_to :section
end

class Checklist < ApplicationRecord
  acts_as_list scope: :section

  belongs_to :section
end

What I'm aiming to do, is allow the user to drag around each place, checklist, or note in the section. I've opted to use acts_as_list to manage positioning.

The problem I'm experiencing is, the scope on each model isn't global to the section. If I query data as section.places The position of the items may be 1, 2, and 3. If I query data as section.notes The position could also be 1, 2, and 3.

What I'm ultimately trying to do is tell acts_as_list to order based on parent. Is this possible? Should I be looking more into polymorphic relationships to solve this problem?


Solution

  • An alternative might be to use STI (Single Table Inheritance). That way your Note, Place, and Checklist would share the same table and you could declare acts_as_list on the abstract inherited model. STI has its drawbacks though.

    You could also have a concrete model that has a polymorphic relationship to each of Note, Place, and Checklist (1:1). You'd declare acts_as_list on that model. I do this in my content management system:

    class ComponentInstance < ApplicationRecord
      belongs_to :section
      belongs_to :instance, polymorphic: true
      acts_as_list scope: :section
    end
    
    class Note < ApplicationRecord
      has_one :component_instance, as: :instance, inverse_of: :instance
    end
    
    class Place < ApplicationRecord
      has_one :component_instance, as: :instance, inverse_of: :instance
    end
    
    class Checklist < ApplicationRecord
      has_one :component_instance, as: :instance, inverse_of: :instance
    end
    

    I've adapted it to your setup but you'd probably want to change the name of the ComponentInstance class. Hope that helps :)