Reputation: 1140
I have a library that defines a base class that all other classes derive from. Rails, on initialization, should provide all of the classes from this library. Rails, however, doesn't recognize class methods inherited from my library class. Here is an example:
Model: app/models/mailing_address.rb:
require 'account_model'
class MailingAddress < AccountModel
# class accessors, initializer and method
end
Library class: lib/account_model.rb
###################################
# AccountModel
#
# This is a super class to be inherited by
# the domain classes of this application.
# Responsible for api calls and
# error handling.
##
class AccountModel
class << self
def get_all id = nil
# class method implementation
end
##
# get id
# fetch method, parses url provided by child class in path hash
# and performs appropriate fetch
# method returns class instance set by fetch
def get id
# class method implementation
end
def update_existing options
# class method implementation
end
def create_new options
#class method implementation
end
def delete_existing id
# class method implementation
end
end
These methods wrap api calls using the HTTParty gem. On load, the methods get
and get_all
are recognized. However, create_new
, and update_existing
are not:
app/controllers/mailing_address_controller.rb:
def update
@mailing_address = MailingAddress.update_existing params[:mailing_address]
. . .
end
Throws the following error:
Processing by MailingAddressesController#update as JSON
. . .
Completed 500 Internal Server Error in 133ms
NoMethodError (undefined method `update_existing' for MailingAddress:Class):
app/controllers/mailing_addresses_controller.rb:17:in `update
In Passenger, I need to reload tmp/restart.txt, in WEBRick, I need to restart the server.
I do not see this behavior in the IRB.
Here is what I've tried so far with no success:
I have never seen this behavior in a rails app before, I have another library class that works just fine.
I'm running: - ruby-2.1.1 - rails 4.03 - passenger 5.07
UPDATE:
While attempting to investigate this further, I uncovered yet another issue:
I added a class method to MailingAddress:
class MailingAddress < AccountModel
. . .
def self.debug_methods
return self.methods
end
Which also throws a "MethodNotFound" exception. Since this does work in the rails console, but not in WEBRick or Passenger, I'm tempted that there is some server caching going on.
UPDATE
After shutting everything down and restarting, Now the situation is reversed:
-WEBRick processes the request successfully -Passenger processess the request successfull -Rails console throws an error:
Webrick and passenger:
Processing by MailingAddressesController#update as JSON
. . .
Completed 200 OK
Console:
MailingAddress.update_existing params
NoMethodError: undefined method `update_existing' for MailingAddress:Class
I'm guessing it's first come first serve as to whomever gets the loaded class.
config.autoload_paths is set correctly:
config.autoload_paths += %W(#{config.root}/lib)
LAST UPDATE
The only workaround that seems to work is clobbering my tmp/ directory and restarting everything (Passenger need to have touch tmp/restart.txt
ran).
This, however, is a crappy workaround. I say bug!
Upvotes: 2
Views: 1154
Reputation: 1140
The server (Passenger, WEBRick) doesn't reliably load library classes as expected. This could be due to the fact that the library class has static methods as well as the derived classes. Those may not be accurately namespaced.
This behavior occurs when a change is made to the application (controller, model, etc.) Even though the library code may not change, the namespacing gets messed up. The console loads application state each time it is invoked where Servers possibly cache application state.
Clearing the tmp directory, and restarting passenger is a valid workaround. Any changes to the code would have to be treated as library changes.
Upvotes: 0
Reputation: 6952
You have to call that method on an instance of the class:
MailingAddress.new.update_existing params[:mailing_address]
or
@mailing_address.update_existing params[:mailing_address]
If you don't need update_existing to be an instance method you can move it outside of the self block.
Also, you might consider just putting your account_model.rb file in app/models. That way you won't have to require it at the top of mailing_address.rb
Upvotes: 0