简体   繁体   中英

Re-opening a class located in lib folder (Rails 3)

Similar questions have been asked many times. However, I have slightly different scenario and I still to find a clean solution to the following problem while developing a Rails 3 app:

I have a ruby code located in a single file. This code is one module MyModule which contains a bunch of classes. I can't modify this code because it's auto-generated by an external tool. The file name is my_module.rb and it resides in the lib folder. This is the usual place for a code which doesn't belong to the main web app. I made sure it is auto-loaded once I access MyModule in one of my app controllers by modifying config.autoload_paths setting in application.rb .

Now I need to re-open one of the classes in MyModule . I created a separate file some_class.rb where I put the following code:

class MyModule::SomeClass
        def some_new_method
           ...
        end
    end

My question is: what is the best place to put this code? And what should be the name of the file?

The things I tried:

  1. Placing the code into initializers folder. it works fine in production environment. However, it breaks in development because the code in initiliazers folder is loaded once when the server starts up and lib is reloaded on each request. So, the first request in development works fine, however, the subsequent requests fail. Also I don't like placing the code into initializers because it's not really initialization piece but rather a part of business logic.
  2. Placing the code into lib folder also doesn't work. It's not loaded. Only my_module.rb is.
  3. Placing the code into lib or some other folder under app and then explicitly requir ing it in controllers. Again it works in production but fails in development for the same reason aforementioned in case #1.
  4. I switched off auto-loading, placed both my_module.rb and some_class.rb into lib folder and require ed them in an initializer. I think this is the best approach. The downside is that I still have to create a custom initializer and the code is not loaded lazily.

UPDATE: 5. Thanks to raggi's suggestion, with auto-loading switched on, I put require_dependency 'some_class' in my controller. In this case some_class.rb is loaded on each request in development mode. This is my preferred approach . However, it still requires some sort of require :)

Remember that files in lib folder are auto-loaded lazily. Rails checks the folder only when you use modules or classes that rails can't find. The file name must follow the naming convention, hence the name my_module.rb .

I wonder if there is a solution when both files are auto-loaded lazily without any require statements.

您是否在控制器中尝试了require_dependency而不是require?

You can put the files in the lib directory and have them not lazily loaded but autoloaded, in config/application.rb if you want to put files in different subfolders:

config.autoload_paths += Dir["#{config.root}/lib/**/"]

Or if you need only the lib folder:

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

TL;DR: Hide the require outside of your mainline code.

I ran in to a similar problem when trying to create a validator within a module during development. I ran across this blog entry when I was trying to solve what sounds like the same problem.

// Added to application.rb
Rails::Application.config.autoload_paths.each do |d|
  Dir["#{d}/*.rb"].each do |p|
    puts "Requiring '#{p}' on startup..."
    require p
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM