brendon / acts_as_list

An ActiveRecord plugin for managing lists.
http://brendon.github.io/acts_as_list/
MIT License
2.04k stars 355 forks source link

Rails 6.0 NoMethodError (undefined method `acts_as_list') #355

Closed tbcooney closed 3 years ago

tbcooney commented 5 years ago

I'm using Rails 6.0 with gem 'acts_as_list', '~> 0.9.19' (I've also tried lower versions), and can not seem to get acts_as_list working. Below is an example trying to grab the last image, to later perform a positional change.

irb(main):009:0> sp = StorageProperty.first
  StorageProperty Load (0.3ms)  SELECT "storage_properties".* FROM "storage_properties" ORDER BY "storage_properties"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<StorageProperty id: 1, name: "ABC Storage", created_at: "2019-08-12 00:52:19", updated_at: "2019-08-15 21:22:41", stripe_id: "cus_FbuU7fMjwIR2Sj", card_brand: "MasterCard", card_last4: "4444", card_exp_month: "2", card_exp_year: "2023", email: "info@abcstorage.com", onboarding_completed_at: "2019-08-15 04:05:33", status: "active", street_address: nil, secondary_address: nil, city_name: nil, province: nil, postal: nil, country: nil, phone_number: nil, card_token: nil, plan_id: nil>
irb(main):010:0> sp.images.last
Traceback (most recent call last):
        3: from (irb):10
        2: from app/models/image.rb:1:in `<main>'
        1: from app/models/image.rb:5:in `<class:Image>'
NoMethodError (undefined method `acts_as_list' for #<Class:0x00007ff0935b8ea8>)

Models

class StorageProperty < ApplicationRecord
    has_many :images, -> { order(position: :asc) }, dependent: :destroy
    accepts_nested_attributes_for :images
end

class Image < ApplicationRecord

  belongs_to :storage_property

  acts_as_list scope: :storage_property

  has_one_attached :file
  delegate_missing_to :file
  validates :file, presence: true

  scope :positioned, -> { order(position: :asc) }
end
brendon commented 5 years ago

Hi @tbcooney, this sounds familiar. Another user had the same problem: https://github.com/swanandp/acts_as_list/issues/303

However their fix was not that helpful to you. The main issue here is that your model class is being initialised before acts_as_list has been injected into ActiveRecord::Base. Something in your setup must be triggering this. Often it's because one is referencing the class name (as a class name, not a string) somewhere in the Rails initialisation logic. If that facility allows you to pass a string instead of a class (e.g. 'Image' not Image then do that instead.

I hope that gives you something to go on. Please post your results back here so that it can help others :)

tbcooney commented 5 years ago

Thanks for the response @brendon ! Real head scratcher for me.

In terms of set up, I'm not doing anything "fancy" per say that would trigger this or touch the Rails initialization logic. I'm following the same set up steps for both dummy applications - steps that worked in 'rails', '~> 5.2.0' with gem 'acts_as_list', '~> 0.9.17' and failing in Rails 6.0 on 'acts_as_list', '~> 0.9.17' and 'acts_as_list', '~> 0.9.19'.

Could you elaborate on passing a string instead of a class to the facility? I'm not exactly sure what that means :/

brendon commented 5 years ago

Thanks @tbcooney. It's a strange one.

Some libraries such as sorcery ask for a model to use for the 'user' in the system (as an example). This is defined in an initialiser file, and if defined as a class constant, will initialise the class at that point. They give you the option to pass the class as a string so that it can be constantised later on.

It'd be ideal if the stack trace could trace where the class is being initialised.

In the past I've been stung by using straight class constants inside other constants on a model. It can create circular reference problems etc...

Sorry I can't be more specific in your instance. Are you able to reproduce this on a bare-bones rails install?

tbcooney commented 5 years ago

Right on - yeah this is pretty bare-bones; I've only created two models through a has_many association. One of the models has an position attribute that is an integer. I start to run into the error manipulating that position in console. Specifically, I have a list of photos where I'm trying to make one image become the cover photo of that list (designated through position 1).

andreyuhai commented 3 years ago

I've got the same issue with Rails 6.1.3. Any luck finding a solution to that?

brendon commented 3 years ago

Hi @andreyuhai, this one can be tricky. Are you doing anything to initialise your class too early in the boot up process? Simply referring to the class in an initialiser can cause it.

andreyuhai commented 3 years ago

Hi @andreyuhai, this one can be tricky. Are you doing anything to initialise your class too early in the boot up process? Simply referring to the class in an initialiser can cause it.

Sorry for the late reply, I figured that it was my fault. I had not restarted the server.

brendon commented 3 years ago

Yep, that'd probably do it :D