Determine rails environment from a gem - ruby-on-rails

I'm working on a rails gem, in which I have some logic that I'd like to be conditional based on the rails environment.
The following code errors out:
if Rails.env.production?
When running in the test app this gives me:
undefined method .env for Gemname::Rails::Module
So, how do you find the Rails environment from a method call in a module that's in a gem?

You have a Rails module in your project, and the constant lookup is finding it, rather than the top-level Rails module. You can either use the top-level constant:
::Rails.env.production?
Or you can just check the environment variable:
ENV['RAILS_ENV']

Related

Rspec - where is the extra configuration for test environment?

I am using the default test for different purposes and I have decided to make a specific rspec environment configuration for running the test suite.
However, I discovered that upon changing to ENV["RAILS_ENV"] ||= rspec in my rails_helper.rb file, suddenly a LOT of things are going wrong, constants are not being loaded (FactoryGirl, DatabaseCleaner, etc. throw uninitialized constant errors)
My question is, where is the code that loads those guys in test environment ? Since I am planning to use this stage for other purposes than running automatic tests, I'm afraid this "out of nowhere" added configuration might not work well with what I am planning to do.
From the perspective of Rails, the test environment is configured and loaded like any other environment such as production or development. You can see this prefixing RAILS_ENV=test to many of the native Rails commands e.g. RAILS_ENV=test rails c will load the rails console for the test environment, and so on. Similarly, all test-specific configuration within Rails is defined in test.rb in your config/environments folder.
However, when you run your specs with rspec spec, you're actually starting the RSpec runner, which, for most intents and purposes, runs independently of Rails (even with the rspec-rails gem).
By convention, when RSpec starts the first thing it does is read command line args from the .rspec in the current directory, if it exists. Then it runs spec_helper.rb (and also rails_helper.rb for rspec-rails 3+). It's actually the spec_helper.rb which does all the heavy-lifting in loading the Rails environment for your tests, along with any of the modules you're using in tests, such as DatabaseCleaner, FactoryGirl, etc.
If you're wondering how RSpec hooks into Rails, the bulk of it is performed in this line, which bootstraps Rails.
require File.expand_path('../../config/environment', __FILE__)
Now, as to your question, without the ENV['RAILS_ENV'] ||= 'test' statement, the above line will load Rails in the default environment (development), which isn't what you want, since any gems not in the :test group will not be loaded, and environments/test.rb will not be loaded either.
TL;DR
Test configuration is handled by two files: spec/spec_helper.rb (sometimes named rails_helper.rb) and config/environments/test.rb. The former configures RSpec and any objects and modules which will be used specifically within the files used in spec, the latter configures your Rails app itself. Omitting ENV['RAILS_ENV'] ||= test loads the development environment and gemsets instead of the test environment and gemsets, which is why you're getting a ton of errors.
If you are getting uninitialized constant errors for FactoryGirl, DatabaseCleaner etc, you most likely included them to test group in your Gemfile.
You should move them to rspec group, eg:
# Gemfile
group :rspec do
gem 'factory_girl_rails', '~> 4.0'
gem 'faker'
end

Creating models from lib directory in Rails 4

I have a file lib/stock_reader.rb in which I'm trying to create a model like so:
module StockReader
def self.create_company_reports(company_data)
CompanyReport.create(name: company[:name])
end
end
In another file, lib/curate.rb, I call this method:
require_relative 'stock_reader'
StockReader.create_company_reports(company_data)
But I receive the error:
/Users/me/code/applications/curator/lib/stock_reader.rb:38:in `block in create_company_reports': uninitialized constant StockReader::CompanyReport (NameError)
from /Users/me/code/applications/curator/lib/stock_reader.rb:37:in `each'
from /Users/me/code/applications/curator/lib/stock_reader.rb:37:in `create_company_reports'
from lib/curate.rb:12:in `<main>'
It seems that my lib directory is failing to recognize my model's existence in app/models/company_report.rb:
class CompanyReport < ActiveRecord::Base
end
I'm guessing this may be because the lib/ directory is being loaded before app/models, but I'm not sure.
I've looked at Accessing models from within the lib directory in a Rails 3 project but I can't see where my lib/ directory is being required in any rakefiles.
It happens when I test lib/curate.rb by running $ ruby lib/curate.rb
Well, that would explain it.
Ruby doesn't know anything about CompanyReport. Rails knows where to find your models because it has a ton of code that handles autoloading classes, but Ruby isn't Rails. If you want code to use Rails' features, you need to run the code in the "Rails environment."
There are a few ways to do this. If you want to run an arbitrary script (like lib/curate.rb) in the Rails environment, you can use the rails runner command:
$ bin/rails runner lib/curate.rb
The Rails console is also very useful for testing:
$ bin/rails console
Loading development environment (Rails 4.1.6)
irb(main):001:0> require Rails.root + "lib/curate"
It's pretty rare to use the ruby command in a Rails project, because usually you want to use Rails' features. You'll probably use the above commands a lot more often.
The problem is that CompanyReport class does not exist in the StockReader module where it's looking for it. To use the top level CompanyReport model preface the class name with ::
::CompanyReport.create(name: company[:name])

Reading 'RAILS_ROOT' variable inside a plugin in Rails 2.3.8

I'm creating a plugin for my Rails 2.3.8 and inside my plugin's init.rb file I have the following code
"#{RAILS_ROOT}/log/myerror.log"
I'm trying to create a 'myerror.log' file in log/ folder), but it seems like plugin can't read the RAILS_ROOT variable (I'm getting the following error in my plugins unit tests:
`const_missing': uninitialized constant RAILS_ROOT (NameError)
I did some web-searching but couldn't find an answer. How to run unit tests with in a plugin with 'RAILS_ROOT') variable, or what are the other best practices?
I'm running on Rails 2.3.8 on Linux.
You should define the RAILS_ROOT constant by using
RAILS_ROOT = File.join(File.expand_path(File.dirname(__FILE__)), '../../../')

How to use Rails'Active Record in a separated script.rb?

I have to run this script: /scripts/saveData.rb
And in it, I need to use ActiveRecord of my Rails application.
I tried to invoke Class, but I get error "uninitialized constant (NameError)".
How can I get a reference to the Rails classes from my saveData.rb script?
Rails 3.1
UPDATED: how i can invoke a method of a Model? My model is: "Program" (also Active Record). I tried with "Program.method" but it doesnt works, why?
Which version of rails you are using?
You can run your code in Rails runner like this if you are using Rails 3:
http://guides.rubyonrails.org/command_line.html#rails-runner
$ rails runner script/saveData.rb
If you are using Rails 2, try this one:
$ script/runner script/saveData.rb
Use rails runner.
Barring that, you could create a rake task, or just load the file from the rails console.
You could try to require the Rails environment with this at the top of your script:
require File.expand_path(File.join(File.dirname(__FILE__), 'config', 'environment'))
However, you should really consider using a rake task instead.

What is the correct way to load modules/classes from lib/ when using the config.threadsafe! option?

I've been working on getting our Rails 2.3.8 app running correctly under JRuby. Everything works great until I enable config.threadsafe! in order to achieve the concurrency that JRuby offers. This caused modules and classes in lib/ to no longer autoload.
with config.threadsafe! enabled:
$ ruby script/runner -e production 'p Sim::Sim200Provisioner'
/Users/amchale/.rvm/gems/jruby-1.5.1#web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in `const_missing': uninitialized constant Sim::Sim200Provisioner (NameError)
from (eval):1
with config.threadsafe! disabled:
$ ruby script/runner -e production 'p Sim::Sim200Provisioner'
Sim::Sim200Provisioner
The file in question is lib/sim/sim200_provisioner.rb where Sim is app/models/sim.rb. Rails normally has no trouble finding and loading the file.
Do I need to manually require all of our libs, or is there a more Rails-like way to handle it that I'm missing?
The documentation of threadsafe! mentions that it disables automatic dependency loading. The reason is that there might be race conditions during the loading of files if two or more threads both decide they are still missing a certain class.
Instead, you should manually require all files you need in an initializer.
Change config.autoload_paths to config.eager_load_paths
(based on Rails issue #6850 and Force reload! from lib directory in rails 3.2 console, Adding lib to 'config.autoload_paths' in Rails 3 does not autoload my module)
The documentation link contains no info, thus here's some relevant doc for #threadsafe! :
Enable threaded mode. Allows
concurrent requests to controller
actions and multiple database
connections. Also disables automatic
dependency loading after boot, and
disables reloading code on every
request, as these are fundamentally
incompatible with thread safety.

Resources