开发者

How can I extend ActiveRecord from app/modules?

开发者 https://www.devze.com 2023-03-11 05:39 出处:网络
I have several different acts_as_... custom class methods I\'d like to use in my app. I would like the code for those methods to be in files in the app/modules directory.

I have several different acts_as_... custom class methods I'd like to use in my app. I would like the code for those methods to be in files in the app/modules directory.

I have been unable to get this working.

For instance, I have a file: app/modules/acts_as_lockable

module ActsAsLockable

    def acts_as_lockable
        before_create :set_lock

        include InstanceMethods
    end

    module InstanceMethods
 开发者_开发技巧       protected

        def set_lock
            now = Time.now.to_s
            self.lock = Digest::SHA1.hexdigest(now)
        end
    end

end

ActiveRecord::Base.extend ActsAsLockable

And in application.rb

config.autoload_paths += %W(#{config.root}/app/modules)

When I try to load up a model that calls acts_as_lockable I get the following error:

NameError: undefined local variable or method `acts_as_lockable'

My guess is that I shouldn't be autoloading the modules folder because ActiveRecord has already been loaded when I extend it? Is there another way to do this? I would like to be able to alter the file during development without restarting my server but that's more of a want that a need.


I think you're thinking about this in the wrong way.

You are adding this module to the load path,

but it will only load if you either say;

require 'acts_as_lockable'

or

ActsAsLockable

I'd suggest you never really want to say either of these inside your code.

The correct paradigm you're looking for is an "initializer".

I suggest you create a file called "config/initializers/acts_as_lockable.rb"

In this file you can either include the whole code,

or just include a require 'acts_as_lockable'

Normally I keep things like this inside the libs directory

ensure lib is in the load path

** config/application.rb **

config.autoload_paths += %W(#{config.root}/lib)

** lib/acts_as_lockable.rb **

module ActsAsLockable

  def acts_as_lockable
    before_create :set_lock

    include InstanceMethods
  end

  module InstanceMethods
    protected

    def set_lock
      now = Time.now.to_s
      self.lock = Digest::SHA1.hexdigest(now)
    end
  end

end

then in the initializer

** config/initializers/acts_as_lockable.rb **

require 'acts_as_lockable'
ActiveRecord::Base.extend ActsAsLockable


The problem is that ruby autoload mechanism is a lazy process: When a constant like ActsAsLockable is used within your code, it looks for a file called acts_as_lockable.rb within the autoload_paths. As You never actually use ActsAsLockable, the file never gets loaded. You could do (although not tremendously beautiful):

ActsAsLockable

class MyModel < ActiveRecord::Base
  acts_as_lockable

  ...
end

I think the acts_as_* pattern is ment to be used be plugins and gems to easily integrate functionality into your code. Plugins and gems are supposed to be in a final state when you integrate them into your project so you would not need the reloading functionality for the development mode.

I hope this helps.

0

精彩评论

暂无评论...
验证码 换一张
取 消