Ruby on Rails - using modules from a different directory - ruby-on-rails

This is a very basic question, but I can't find exactly the answer I need.
I have the following code in trunk/app/models/parsers/my_file.rb in my dev environment:
def initialize
...
#logger = Utils::SingletonLogger.get_logger
#logger.debug("Instantiating my_file object")
end
It runs fine.
But when I deploy it to the test environment (all code should be identical, but I'm not sure where to start looking for differences if there are any), Rails complains that it can't find Parsers::MyFile::Utils. The Utils module I want to use is in app/lib/my_utils.rb. This makes me think that Rails is creating some sort of namespace for the code in the parsers sub-directory, and only looking there for the Utils module, but I haven't been able to figure out how to make it work for me. Is there some main, application level prefix I can use to specify to look outside of the current directory structure?
I've tried adding require 'my_utils' and require_relative '../../../lib/my_utils.rb'. The former can't find the file, the latter just throws the same error as when I don't have any require at all. I'm not sure if I should have to require this or not.
In any case, I clearly don't quite understand how to refer to code in modules in a different directory, I don't understand when/why rails needs an explicit path at some times/environments but not others, and I don't know how to make Rails look outside of the current file for code. Any help with any of these would be appreciated.
Oh, I'm using Ruby 1.9.3, and rails 3.2.1.
Edit: It just started working, without any changes to the application.rb or environment files. It doesn't even have a require in the current version. Is there any obvious reason for it not to work at first, then to work after another server restart? (I'm pretty sure I restarted it after the code went in - I don't think I just forgot to do that before.)
Anyway, thanks for your help - I really do appreciate it.

You can manually add directories you want to include in application.rb. Might want to make sure in your application.rb or test.rb config files you have this autoload_paths in there, yours might be specific to your development.rb file.
config.autoload_paths += %W(#{config.root}/lib/)

Related

Problems with loading and including a module (dev vs. test)

I think I understand the basics of requiring and including modules* in Ruby on Rails, but I can't figure out what's going on with an issue I'm having. I'm using Ruby 1.9.3 with Rails 3.2.1.
I have a module called Utils in /lib/_utils.rb, which currently just has some logging functions in it. In most other files in the app, I'm able to execute the following code and use the logger without any problem:
logger = Utils::SingletonLogger.get_logger
Note that in model code, I generally use an instance variable instead of a local variable, and that seems to work fine as well.
Also note that this does NOT require me to have
include Utils
in the code.
The problem is that, in at least one controller, I have to explicitly require and include the module before it will work. Well, usually anyway. Most of the time I get a NameError because it doesn't recognize Utils as a constant. Other times, it throws a ransack error. And once it a great while, it just works. If I add just the include Utils line, I get a similar NameError, though with a shorter error message.
And best of all, this only happens in the test environment, and not in my local dev instance.
For now, I've commented out all the logging in this one file, but I'd like to understand what's going on. I've added
config.autoload_once_paths += %W(#{config.root}/lib)
to application.rb, thinking this would insure that the actual code is available to any file in the application. I guess I'm supposed to need
include Utils
in every file that uses this module, but I don't understand why that doesn't seem to be required in other files, or why I should have to re-require the module file in this controller.
I'd appreciate any insight or guidance.
*Briefly - require/load reads the module's actual source code file into memory, include makes the module's methods available in a different file. I assume that I really only want to require/load a file once per instance of the application - that having it executed every time a new class is used is unsightly at best, and inefficient at worst.
I think the problem involved some combination of the following:
The module's file name didn't match the name of the module, so it didn't get picked up by the autoload.
I had an explicit require statement in a couple of files, but not others. I think when the files containing the require were executed before ones that weren't, the system could find the module, otherwise, it couldn't.
At least during the troubleshooting, I sometimes had the include statement outside of class definitions, which apparently is non-standard at best, meaningless at worst.
I used the module name as a prefix, which seems to work okay when everything else is set up correctly, but may have confused the interpreter at other times. I think this is standard when calling module methods directly, and it may mean that you don't have to include the module, though I'm not sure on that point yet.
I had a model's initialize method overridden, which may not have contributed to this problem, but did throw exceptions that interfered with debugging.
I still don't know why this flaked out in test, but not in dev.
I use Rails 3.2.11
Please follow the path
Users ▸ [your username]▸ .rvm ▸ gems ▸ ruby-1.9.3-p545 ▸ gems ▸ railties-3.2.11 ▸ lib ▸ rails ▸ engine
access file : configuration.rb
replace
paths.add "lib", :load_path => true
by
paths.add "lib", :eager_load => true
Hope this help!

Are Rails engines supposed to come with an environment.rb?

I recently created my first Rails engine. The only thing in /config is routes.rb - no environment.rb or application.rb or anything like that.
When I installed the rspec-rails gem and tried to run my specs, I got an error saying it couldn't find environment.rb, which is not surprising, since environment.rb doesn't exist.
The confusing thing to me is that the evidence I have tells me one of two things must be the case:
1) Rails engines don't come with an environment.rb and you're expected to create environment.rb, application.rb, etc. by hand. This seems unlikely.
2) Rails engines do come with an environment.rb, but my engine happens to be missing it for whatever reason. This also seems unlikely. I am confused, though, by this answer that refers to environment.rb in an engine: Testing Rails 3.1 mountable engine with Rspec
So my question is: Are Rails engines supposed to come with an environment.rb, and if not, how are you supposed to create one if you want/need one?
Use the dummy app's environment.rb file.
To setup RSpec:
Add the below to your spec_helper.rb file.
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../test/dummy/config/environment", __FILE__)
...
It's also helpful to add the engine root.
ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../')
If you want access to the engine's routing helpers, add the below in the RSpec.configure block.
# This will include the routing helpers in the specs so that we can use
# <engine>_path, etc., to get to the routes.
config.include <RailsEngine>::Engine.routes.url_helpers
Hope that helps.
Rails engines may have environment files, but they don't need them. I would recommend against them, because your application is probably going to get mounted (as a gem) inside of another application, making it very difficult to configure your engine from within the main rails application.
It's more advisable that you use a yml file that can be configured from within the primary rails app, and allow that rails app to implement environment specific configurations. That doesn't mean you can't have some defaults that are based on environment environment files inside of your rails engine, but rather, that it usually makes life easier to allow external configuration.

Writing a Gem -- How to manage configuration settings?

I'm new to the gem-writing world, and I'm trying to make sure that my gem is as flexible as it can be out of the box. I've got a couple configuration options that will need to be set for things like testing, but I'd like for those options to be able to be overridden at the Ruby on Rails level.
I know that certain gems like Devise do this already, but I'm not sure exactly how it should be accomplished (primarily from the "put these files here, put those files there" kind of perspective). Can anyone give me any tips or suggestions?
Edit: What I'm really looking to know is how these gems manage having configuration settings defined locally to the gem and having them defined in Rails, and defining for the Rails application which takes precedence.
there are gems that help you create rails initializer style configuration.
an example is https://github.com/phoet/confiture/

Where do you put an object call that is needed before your application loads?

I have an object call that is basically initiating a singleton that is needed all over my application. I thought the best place to put this was the environment.rb file, right after the Application.initialize! call. And it had worked with all my tests. But now that I'm running my code in the development environment, I'm finding that it is not getting called. Is there somewhere else I should be putting it, or is there something wrong with my development environment setup?
EDIT: I haven't looked at the answers yet, but I did find out that it's not working in development when I have the config.cache_classes set to false.
Try putting it in an initializer file.
See this link for configuring rails.
Basically, I do use config files written in yml and load these with an initializer.
If you don't want to go into details, use Ryan Bate's gem: nifty-generators
and type in console:
rails g nifty:config
It will install everything for you. Then edit your config/app_config.yml file.

Automatically reload rails module

I'm developing a ruby module that I include in my rails app. I want it to be reloaded automatically when it changes. I've done extensive googling, and looked at the various questions here that discuss it, but they all seem out of date or wrong.
How do I get an external module to be reloaded in rails when it changes? I've tried adding its name to ActiveSupport::Dependencies.unloadable_constants, but after I type reload! in the console, I can no longer refer to that symbol without a NameError: uninitialized constant foo, even if I do another require 'foo_module'. Does anyone know how to get this working?
Note: here is one possible dup, but note in the comments to the 'answer' that it never solved the problem for modules. There's also this question which has a dead link in the answer, and finally this one, which also doesn't solve it.
I found how to do this:
Make sure FooModule is in lib/foo_module.rb.
Use require_dependency to require your external library in lib/foo_module.rb.
These steps are both required, and no others are required.
There are two separate problems here.
The simpler of which is that you are using require, when you want load.
require will evaluate the code in a file once, no matter how many times that file/module is required.
load will evaluate the code in a file each time that file is loaded.
require is preferred to load used so that the files are not evaluated multiple times when many files depend on them.
The short version is that load can be used to reload modules that have already been loaded by require.
The more complicated problem is automatically reloading a module on change.
One of the possible duplicates listed in the question links to here. Which suggests prefixing any code that depends on your module with a conditional load of your module if it has changed since loading. You'll need to use a global variable to keep track of when a file was loaded.
N.B.: this should not be used on a production server, but should be fine on a development server or console.
I spent sometimes to research this issue as well.
Here's my findings on how to auto-reload require files in Rails without restarting server.
The solution is now available as a Ruby gem require_reloader.

Resources