Home > Enterprise >  How do I provide a default class definition from /lib in Rails?
How do I provide a default class definition from /lib in Rails?

Time:09-14

I'm presently using a git subtree to manage a directory of classes/libraries somewhere under /lib. The idea is to share common classes and libraries from that directory between different projects that I manage. In it are default implementations of various classes, such as models, controllers, etc. The desired result is that any application I set up which has this subtree would not HAVE to define or customize the classes that come with default implementations, but can if needed.

For example, I have a default User model, and wish to include it automatically so that there is no need to define one in /app/models. The problem is that if I DO automatically include it, and then additionally define a User class in /app/models (say to add or override a method or some configs), that definition will never be included because the class already exists.

I'm attempting to take advantage of the fact that a class can be defined twice in Ruby, and it'll more or less "merge" the definitions. For example, defining a User class twice in the following way will result in a single User class with methods for both User.foo and User.bar:

class User
  def self.foo; 'foo'; end
end

class User
  def self.bar; 'bar'; end
end

The best way I've come up with to do this so far is to write code in an initializer like the following (note that the to_underscores method isn't a standard String method, it's my own):

Rails.configuration.to_prepare do
  [
    User,
    # more classes...
  ].each do |klass|
    filepath = Rails.root.join("app/models/#{klass.name.to_underscores}.rb")
    require filepath if File.exist? filepath
  end
end

I could clean this up a bit perhaps by looping through class definitions which exist in key subdirectories under /lib so I don't have to manually list out class names that can be extended/overridden in this way, but I feel like there's got to be a better way. This list will be pretty long and a little silly to try and manage, not to mention it'll be a lot trickier with classes defined in a directory structure with subdirectories. I'd like something more automatic. Any thoughts??

CodePudding user response:

You're getting bitten by lazy loading and rails' constant resolver. If you already load a User either from app/models or lib, rails won't think of looking for other definitions of this class in other places.

You can do what you are doing now. Or turn eager loading on (in your config/*.rb, set config.eager_load = true)

CodePudding user response:

Why not use inheritance? So your User model inherits default behaviour from DefaultUser

class User < DefaultUser

end

class DefaultUser < ActiveRecord::Base

end

You can include the DefaultX classes by making a gem to import in Gemfile that has all of these default classes defined.

  • Related