Creating models from lib directory in Rails 4 - ruby-on-rails

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])

Related

Upgrade to Rails 4.0.5 results in uninitialized constant Surveyor::Helpers

I have been using the surveyor gem within Rails 3.2.x without any issues in my project.
The gem defines modules that reside within the lib subdirectory of the gem.
Example
lib/surveyor/helpers/surveyor_helper_methods.rb
Then in my app/helpers directory I include the module and extend like follows.
include Surveyor::Helpers::SurveyorHelperMethods
This works fine in Rails 3, but within Rails 4 it results in the error Uninitialized constant Surveyor::Helpers.
As a test I copied the directory from the gem directly into my projects lib directory structure and this got rid of the error; so it seems the include is no longer looking at the gems' lib tree. Moving all of the files directly up into my project isn't a good solution. Is there another way to work around this?
in your helper , just include this file..so it will be something like
require 'surveyor/helpers/surveyor_helper_methods'
module UserHelper
include Surveyor::Helpers::SurveyorHelperMethods
end

Determine rails environment from a gem

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']

RSpec Can't find Ruby Files/Classes

I'm using rspec 2.10 with Rails 3.2.1 and have problems with classes not being found.
I have put a class called DbTasks under a dir app/util. Under spec, i've created file util/db_tasks_spec.rb which runs afer i included the line:
require File.join(File.dirname(__FILE__), '../../app/util/db_tasks')
However, rspec now isn't able to find my models. I don't want to have to include these manually. Is there a way to config rspecs paths so everything gets found?

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.

How to test Rails 3 Engines with Cucumber & Rspec?

I apologize if this question is slightly subjective... I am trying to figure out the best way to test Rails 3 Engines with Cucumber & Rspec. In order to test the engine a rails 3 app is necessary. Here is what I am currently doing:
Add a rails test app to the root of the gem (myengine) by running: rails new /myengine/rails_app
Add Cucumber to /myengine/rails_app/features as you would in a normal Rails app
Require the Rails Engine Gem (using :path=>"/myengine") in /myengine/rails_app/Gemfile
Add spec to the root directory of the gem: /myengine/spec
Include the fixtures in /myengine/spec/fixtures and I add the following to my cuc env.rb:
env.rb:
Fixtures.reset_cache
fixtures_folder = File.join(Rails.root, 'spec', 'fixtures')
fixtures = Dir[File.join(fixtures_folder, '*.yml')].map {|f| File.basename(f, '.yml') }
Fixtures.create_fixtures(fixtures_folder, fixtures)
Do you see any problems with setting it up like this? The tests run fine, but I am a bit hesitant to put the features inside the test rails app. I originally tried putting the features in the root of the gem and I created the test rails app inside features/support, but for some reason my engine would not initialize when I ran the tests, even though I could see the app loading everything else when cuc ran.
If anyone is working with Rails Engines and is using cuc and rspec for testing, I would be interested to hear your setup.
**UPDATE
I changed my setup a bit since I wrote this question. I decided to get rid of the spec directory under the root of the engine. Now I just create a rails app named "test_app" and setup cuc and rspec inside that app like I would normally do in a rails app. Then I include the gem like I did in step #3 above. Since the engine is a sub-app, I guess its just best to test it like it was a normal rails app. I am still interested in hearing if anyone has a different setup.
Rails 3.1 (will) generate a pretty good scaffold for engines. I'd recommend using RVM to create a new gemset called edge and switch to it:
rvm gemset create edge
rvm use #edge
Then install edge rails:
git clone git://github.com/rails/rails.git
cd rails
rake install
From there, you can follow Piotr Sarnacki's mountable app tutorial, replacing calls such as:
bundle exec ./bin/rails plugin new ../blog --edge --mountable
With simply:
rails plugin new blog --mountable --full
The mountable option makes the application mountable, whilst the full option makes it an engine with tests already built-in. To test the engine, this generator generates a folder in test called dummy which contains a small Rails application. You can see how this is loaded in test/test_helper.rb.
Then it's up to you to massage the data to do what it needs to in order to work. I would recommend copying over the cucumber files from a standard rails g cucumber:install into the project and then messing about with it until it works. I've done this once before so I know it's possible, but I cannot find the code right now.
Let me know how you go.
I'll explain how I did it using as example the following gem: https://github.com/skozlov/netzke-core
The testing application. It is in netzke-core/test/rails_app. This app can be run independently, so I can also use it for manual testing or for playing around with new features if I like.
In order for the testing app to load the gem itself, I have the following in application.rb:
$:.unshift File.expand_path('../../../../lib', __FILE__)
require 'netzke-core'
Cucumber features. They are in netzke-core/features. In env.rb I have:
require File.expand_path(File.dirname(__FILE__) + '/../../test/rails_app/config/environment')
... which will load the testing application before executing the features.
Specs. These are in netzke-core/spec. In spec_helper.rb I have the following:
require File.expand_path("../../test/rails_app/config/environment", __FILE__)
... which will load the testing application before running the specs.
Running tests. This setup lets me run the tests from the root of the gem:
cucumber features
and
rspec spec
Factory Girl. Not for this particular gem, but I'm normally using factory_girl instead of fixtures (see, for example, a similar setup in https://github.com/skozlov/netzke-basepack).
A bit late to the party, but here is my strategy:
Generating the rails plugin in 3.2:
rails plugin new blog --mountable --full
This creates test/dummy, containing the dummy rails app
Add the specs to spec
Move the dummy folder to spec (and optionally get rid of the other testfiles)
Adapt specs/spec_helper.rb so it includes
require File.expand_path("../.../config/environment", __FILE__)
instead of
require File.expand_path("../dummy/config/environment", __FILE__)
Execute rails g cucumber:install. It will generate features folder a.o.
Add
ENV["RAILS_ROOT"] ||= File.expand_path(File.dirname(__FILE__) + '/../../spec/dummy')
before
require 'cucumber/rails'
in features/support/env.rb
Now you have features and spec in the root of you project, while the dummy rails app is neatly tucked away under spec/dummy

Resources