Crashalot
Crashalot

Reputation: 34523

undefined class/module X in Rails 3 despite requiring models in initializer

We use Rails.cache and see an undefined class/module X error when loading pages that invoke class X. We followed the suggestion here to include an initializer that requires all models in the dev environment.

However, we see the same error. Any other suggestions? We included the initializer code below, and from the output to the console, it appears like the code is getting invoked.

We're on Rails 3.2.12 + Ruby 1.9.3.

if Rails.env == "development"
  Dir.foreach("#{Rails.root}/app/models") do |model_name|
    puts "REQUIRING DEPENDENCY: #{model_name}"
    require_dependency model_name unless model_name == "." || model_name == ".."    
  end 
end

Stack trace:

Processing by DandyController#get_apps as JSON
  Parameters: {"category"=>"featured", "country_id"=>"143441", "language_id"=>"EN"}
WARNING: Can't verify CSRF token authenticity
Completed 500 Internal Server Error in 2ms

ArgumentError (undefined class/module App):
  app/controllers/dandy_controller.rb:66:in `get_featured_apps'
  app/controllers/dandy_controller.rb:50:in `get_apps'


      Rendered C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.12/lib/action_dispatch/middleware/templat
    es/rescues/_trace.erb (2.0ms)
      Rendered C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.12/lib/action_dispatch/middleware/templat
    es/rescues/_request_and_response.erb (2.0ms)
      Rendered C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.12/lib/action_dispatch/middleware/templat
    es/rescues/diagnostics.erb within rescues/layout (46.0ms)

Code:

def get_featured_apps( country_id )
    # Fetch featured apps from cache or from DB
    apps = Rails.cache.fetch( 'featured_apps', {:expires_in => 1.days} ) do
        logger.info '+++ Cache miss: featured apps'
        get_featured_apps_helper country_id     
    end

    # Get sponsored results



    apps = get_featured_apps_helper country_id
    # Return featured apps
    return apps
end

Upvotes: 3

Views: 1211

Answers (2)

GuyPaddock
GuyPaddock

Reputation: 2517

A more elegant solution is to write a wrapper method you can call around your call to Rails.cache.fetch:

def some_func
  apps = with_autoload_of(App) do
    Rails.cache.fetch( 'featured_apps', {:expires_in => 1.days} ) do
      logger.info '+++ Cache miss: featured apps'
      get_featured_apps_helper country_id
    end     
  end
end

##
# A simple wrapper around a block that requires the provided class to be
# auto-loaded prior to execution.
#
# This method must be passed a block, which it always yields to.
#
# This is typically used to wrap `Rails.cache.fetch` calls to ensure that
# the autoloader has loaded any class that's about to be referenced.
#
# @param [Class] clazz
#   The class to ensure gets autoloaded.
#
def self.with_autoload_of(clazz)
  yield
end

Upvotes: 0

skahlert
skahlert

Reputation: 647

I've overwritten the fetch method which worked wonders for me!

unless Rails.env.production?
  module ActiveSupport
    module Cache
      class Store
        def fetch(name, options = nil)
          if block_given?
            yield
          end
        end
      end
    end
  end
end

Upvotes: 3

Related Questions