Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reload Rails 3 initializer in development mode

I'm building a Rails 3 app where users can select one of a number of templates and build a little website. I'm trying to initialize all of the available templates when the application starts. That's essentially a file that let's me define them all, then calls Template.add(template) for each one of them, which in turn stores them in @@templates and I can access them via Template.find(name).

The problem is that in development mode, the initializer I have making the calls to Template.add are getting loaded on the first request, then wiped out on reload!. I've read about config.to_prepare, but it isn't working for me, likely because I'm requiring the templates like this:

# template config at app/templates/template_name/template_name.rb
path = File.expand_path(Rails.root + 'app/templates')
Dir[File.join(path, '/*')].each do |template|
  name = File.basename(template)
  require File.join(path, name, "#{name}.rb")
end

What can I do to either reload these files after reload! or keep them from getting trashed at all? Also, if you have a recommendation for a better way to handle this, I'm all ears. I'm still getting my footing with Rails, especially in regards to configuration stuff.

I'm temporarily avoiding this problem by loading the data in the class. Save me from this ugly, non-modular nastiness.

like image 471
coreyward Avatar asked Feb 07 '11 18:02

coreyward


2 Answers

I think you ought to be able to do this with config.to_prepare if you move your calls to Template.add out of the template_name.rb files (I am assume that is where they are now), and into your loading code, just after the require. For example, consider adding this class method to your Template class, and then maybe even calling it from the class itself when it first gets loaded:

class Template
  def self.load_all
    # template config at app/templates/template_name/template_name.rb
    path = File.expand_path(Rails.root + 'app/templates')
    Dir[File.join(path, '/*')].each do |template|
      name = File.basename(template)
      require File.join(path, name, "#{name}.rb")

      # Register the template even if the class itself is already loaded.
      Template.add(name)
    end
  end

  # Initially load all templates.
  Template.load_all
end

Then remove the Template.add(name) code from the template_name.rb files where they are registering themselves. (Again, I am assuming this is where that currently happens - I am not quite clear on this from your original post.) Or perhaps you just want to make sure Template.add is idempotent and silently discards duplicates.

Lastly, add the following to config/environments/development.rb:

config.to_prepare do
  Template.load_all
end

That will reload all your templates after the Template class reloads.

I haven't tried this, but with the call to Template.load_all I suggested at the end of the Template class, you may not even need the config.to_prepare part.

like image 130
scottwb Avatar answered Oct 06 '22 01:10

scottwb


How about storing the lookup of template names to their files in a memory store like memcached or Redis, or even in the database. The initializer could load up the memory store or ensure that the database is up to date with all the values, and then Template.find could just look to the store to see where the files are, or even just get the class name if they are already going to be loaded. Simply seeing if the class name is defined can tell you if you need to require the template file or just go ahead and create your new instance.

Basically store @@templates outside of the rails process memory, or at least enough information that you could build the parts of @@templates that you need on the fly.

like image 40
danivovich Avatar answered Oct 06 '22 00:10

danivovich