views:

92

answers:

2

THE SITUATION:

  1. I have code in lib/foo/bar.rb with a simple method defined as such:

    module Foo
      class Bar
        def test
          "FooBar"
        end
      end
    end
    
  2. In my helper, FooBarHelper, I have:

    require `lib/foo/bar`
    module FooBarHelper
      def test_foo_bar
        fb = Foo::Bar.new
        fb.test
      end
    end
    
  3. In my view, I call this helper method like so:

    <%= test_foo_bar =>
    
  4. In my config/environments/development.rb, I added the directory to my config.autoload_paths:

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

THE PROBLEM:

When I change the return value of Foo::Bar.test to, for example, "MODIFIED FOOBAR", the original return value, "FooBar", is still being displayed on the view and not the new value.

Since I'm in development mode, shouldn't the code reload the code on every request?

Could someone tell me what I'm missing?

Thanks!

A: 

Why are you putting the require into the module, when using autoload_path you should not need to require the file at all, it should be working without, I think if you manually require the file afterwards, rails does not know when to load it again?

Something like this:

require `bar`

module FooBarHelper

  def test_foo_bar
    fb = Foo::Bar.new
    fb.test
  end

end

should work, no need for having the require inside your module.

Max Schulze
Thanks for the response Max! Appreciate it! So how do you propose I access my Bar class?
John
I have updated my above answer, does that work for you with reloading?
Max Schulze
No dice on my end... did this work for you?
John
Sorry my mistake, if you have /lib/foo in your load path you only need to require bar in the file. I corrected my example.
Max Schulze
Still seeing the same result...
John
+2  A: 

They removed the lib folder the app root in Rails 3.

You can either add it back
config.autoload_paths << 'lib'
or you can use `require_dependency` in your helper.
module FooBarHelper
  require_dependency 'foo/bar'

  def test_foo_bar
    fb = Foo::Bar.new
    fb.test
  end
end

Both ways tell Rails that your file lib/foo/bar.rb should be autoloaded and subsequently, reloaded each request.

Samuel
Thanks for the response Samuel! Aren't I already using your first suggestion? Should I be using the `<<` operator instead fo `+=`? I thought they were equivalent.
John
For your purpose, they are the same. The difference is you want `lib` to be autoloaded for it to be able to find the `foo/bar.rb` source file for the constant `Foo::Bar`.
Samuel
I updated THE SITUATION section of my post to make it easier to pick apart. See Part 4.
John
So are you saying that I can't or shouldn't be using a more-resolved path in my `autoload_paths` (i.e., `lib/foo` vs `lib`)? I should also make it clear that autoloading is not the issue, but rather reloading when a change has been made to Bar class. Since I'm in development mode, shouldn't it reload the code on every request?
John
Exactly. If you want to use the rails auto class name mapping to filename, `Foo::Bar` must map to `foo/bar.rb` which it can only find if your `lib` folder is in the load path (`$:` or `LOAD_PATH`). --- Not all code gets reloaded on each request (the rails framework for example) and one big change was to remove the `lib` folder from the reloaded files.
Samuel
Let me give this a shot... but what if I don't want everything in the `lib` folder autoloaded? Also, should I remove `#{config.root}`?
John
So I replaced `config.autoload_paths += ["#{config.root}/lib/foo"]` with `config.autoload_paths += ["lib"]`, restarted my app, refreshed my view, it displayed `FooBar`. Changed the return value of my method to `Modified FooBar`, refreshed my view, and it still displayed `FooBar`...
John
Do you still have a `require` statement? Rails doesn't stop you from requiring files and preventing it from reloading them (think libraries that you didn't write). If you use autoload, you cannot use require and must let rails do it. Otherwise use `require_dependency` if you don't want to autoload the lib folder.
Samuel
Nice! Will `require_dependency` auto-reload? I also managed to apply what you stated about the auto-class mapping so that I don't have to autoload the entire `lib` folder by simply creating another folder `foo_lib` and putting `foo` inside of it. Question: Where did you read about this stuff? Because I would definitely like to read more about it.
John
`require_dependency` is a helper in rails to specifically load something and mark it as reloadable.
Samuel
Thanks Samuel. You've been a great help! Can I ask where you read about the auto class name mapping stuff?
John
I'm not sure if there is a document on it, but the relevant methods are underscore (http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-underscore) and camelize (http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-camelize).
Samuel
Thanks Samuel! Really appreciate all the help.
John