"Rake cannot load such file" error in Sinatra app - ruby

I am building a Sinatra app and trying to use ActiveRecord. Rake is not recognizing my controller file and returning rake aborted! LoadError: cannot load such file whenever I run any rake task. Here are my gems:
source "https://rubygems.org"
ruby "2.7.2"
gem 'sinatra'
gem 'thin'
gem 'shotgun'
gem 'require_all'
gem 'activerecord'
gem 'sinatra-activerecord'
gem 'sqlite3'
gem 'rake', '~> 13.0.6'
And here's the Rakefile:
# Rakefile
require 'sinatra/activerecord/rake'
require_relative './app/test_controller.rb'
Any ideas? In the Rakefile, I've tried require_relative for ./app, /app, ../app, etc. Also, I'm on a bit of a time crunch, so if I can't sort this out quickly do I need Rake to use ActiveRecord?

TL/DR:
remove require_relative './app/test_controller.rb' from your Rakefile.
Details:
Rake is a tool that lets us define and run commands from the command line (e.g. rake db:migrate). Activerecord comes bundled with a few rake tasks (like generating a migration file, running one, dumping/loading your database schema, etc) that make it much easier to work with.
Rake tasks are just ruby, so to run a Rake task successfully it will need to load any classes/files it depends on (which is typically handled independently by each rake task). If you're going to write your own rake tasks you'll want to ensure that the tasks require the relevant files. Loading your app (or sinatra controllers) in a base Rakefile wouldn't generally be advised as it wouldn't always be needed.
The exception to this would be if you needed to load some kind of 'boot' or 'config' file in order to setup your database connections/configuration so that the activerecord rake tasks could successfully connect to your database.

Related

Trying to run migrations in Sinatra but can't load Sinatra app

I'm looking to run migrations for a Sinatra app called "sinatra_active_record_start" but can't get my settings right.
When I run bundle exec rake -T I get:
LoadError: cannot load such file -- sinatra_active_record_start
/Users/jasonnappy/ga_wdi/exisiting_resources/wdi_london/resources/materials/local/06-server-applications/ruby/sinatra/active-record/sinatra_active_record_start/Rakefile:1:in `require'
Same as when I run:
bundle exec rake db:create_migration first_migration
My Gemfile is:
source "https://rubygems.org"
gem "sinatra"
gem "activerecord"
gem "sinatra-activerecord"
gem "rake"
gem "thin"
My Rakefile is:
require "sinatra_active_record_start"
require "sinatra/activerecord/rake"
namespace :db do
desc "Migrate the database"
task(:migrate => :environment) do
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Migration.verbose = true
ActiveRecord::Migrator.migrate("db/migrate")
end
end
The top of app.rb is:
require "bundler/setup"
require "sinatra"
require "activerecord"
require "sinatra/activerecord"
I know there are some redundancies, but at this point, I'm just trying to plug in and make something work that I found on the internet.
First, it doesn't look like you are requiring an adapter for your database. Adding one, like
gem "sqlite3"
to your Gemfile, should fix that.
Second, sinatra/activerecord creates migrations in a directory called "db/migrate" by default. That's where your migrations should live, not the root directory.
Move your migration there and remove
require "sinatra_active_record_start"
from your Rakefile. That's the code that is causing the immediate error. You shouldn't need to require each migration in the Rakefile.
Following these steps should make your migrations run, although you should rename the file to follow ActiveRecord convention. Run
rake db:create_migration NAME='sinatra_active_record_start'
to create a new one with a timestamp.
"Sinatra Active Record Starter Kit" is an example repo to help you get started.

Adding a gem dynamically from within a rake task

I am trying to use the mongo gem for a data migration rake task. I don't want to add it to the Gemfile for the whole project just so it can be used from this single rake task. How do I dynamically add mongo to the bundle for just that rake task?
I have tried using Bundler::Injector::inject, but then I need to bundle install. If I run that from within the task, the bundler has already initialized, so the require 'mongo' still fails. Should I do something to reload the bundler or is there actually a clean way to do this?
Add it to your Gemfile with :require => false:
gem "mongo", :require => false
This will allow bundler to install it and set up the load path, but it won't actually load the gem.
In your rake task, just require "mongo" to load it when you need it.

How do I include gems in Rake files without specifying them in a Gemfile?

I am trying to write my first Rake file. It looks something like this:
lib\tasks\routes_check.rake:
require 'curb'
task :route_test do
puts "checking routes"
end
Running rake route_test fails with the message:
rake aborted!
no such file to load -- curb
I ran it with --trace and the trace is here.
I can't figure out why this does not work. In the same lib/tasks directory, I saved a .rb file which looks like:
task.rb:
require 'curb'
puts "Hello"
When I run this file with ruby task.rb, it works fine. What am I doing wrong here?
Rails applications by default use Bundler, so you need to add gem "curb" to your Gemfile and then ”install” (register) the new gem to Rails bundle with gem install.

Running Rake tasks in Rspec Tests

I am building up an integration test suite and there is one bit of logic that I need to have a clean database for. How can I run the db:test:purge task inside of one of my tests?
I am using: ruby 1.9.2, rails 3.0.9, rspec 2.6
You can invoke Rake tasks as following:
require 'rake'
Rake::Task[name].invoke
In this case this would result in the following code:
require 'rake'
Rake::Task['db:test:purge'].invoke
Approved answer didn't work for me, when I needed to execute my own rake task
Here's my solution
Put in the top of the spec file
require 'rake'
Place these lines where you need to execute your custom rake task, e.g. rake update_data from the file example.rake
load File.expand_path("../../../lib/tasks/example.rake", __FILE__)
# make sure you set correct relative path
Rake::Task.define_task(:environment)
Rake::Task["update_data"].invoke
My environment:
rails (4.0.0)
ruby (2.0.0p195)
rspec-core (2.14.7)
rspec-expectations (2.14.3)
rspec-mocks (2.14.4)
rspec (2.14.1)
rspec-rails (2.14.0)
If we require to use multiple rake tasks we can add
require "rake"
Rails.application.load_tasks
Then simply call any task.
Rake::Task['sync:process_companies'].invoke
Though I cant confirm if its slower because it loads all the tasks
for me (rails-6)
Rails.application.load_tasks
Rake::Task['app:sync'].invoke
=> require not necnessary in my case
We need to require the task also
require 'rake'
Rake.application.rake_require 'tasks/new_adapter'
After this, just call the task
Rake::Task['new:adapter'].invoke
Many of the above answers worked for me for running a single spec. However, I had to take an extra step when running multiple specs for a single rake task.
After each spec, I had to run Rake::Task.clear, as (for some reason) the task would not be run again if it was registered as being already_invoked (i.e. if Rake::Task['my_task'].already_invoked returned true.
I added the following line to my rake task spec:
after { Rake::Task.clear }
and everything worked as expected when running multiple tests for the same rake task.

Ruby: What does 'require: false' in Gemfile mean?

Does this:
gem 'whenever', require: false
mean that the gem needs to be installed, or does it mean it is not required?
This means install the gem, but do not call require when you start Bundler. So you will need to manually call
require "whenever"
if you want to use the library.
If you were to do
gem "whenever", require: "whereever"
then bundler would download the gem named whenever, but would call
require "whereever"
This is often used if the name of library to require is different than the name of the gem.
You use :require => false when you want the gem to be installed but not "required".
So in the example you gave:
gem 'whenever', :require => false
when someone runs bundle install the whenever gem would be installed as with gem install whenever. Whenever is used to create cron jobs by running a rake task but isn't usually used from within the rails (or other framework if not rails) application.
So you can use :require => false for anything that you need to run from the command line but don't need within your code.
require: false tells Bundler.require not to require that specific gem: the gem must be required explicitly via require 'gem'.
This option does not affect:
bundle install: the gem will get installed regardless
the require search path setup by bundler.
Bundler adds things to the path when you do either of:
Bundle.setup
which is called by require bundler/setup
which is called by bundle exec
Example
Gemfile
source 'https://rubygems.org'
gem 'haml'
gem 'faker', require: false
main.rb
# Fail because we haven't done Bundler.require yet.
# bundle exec does not automatically require anything for us,
# it only puts them in the require path.
begin Haml; rescue NameError; else raise; end
begin Faker; rescue NameError; else raise; end
# The Bundler object is automatically required on `bundle exec`.
Bundler.require
Haml
# Not required because of the require: false on the Gemfile.
# THIS is what `require: false` does.
begin Faker; rescue NameError; else raise; end
# Faker is in the path because Bundle.setup is done automatically
# when we use `bundle exec`. This is not affected by `require: false`.
require 'faker'
Faker
Then the following won't raise exceptions:
bundle install --path=.bundle
bundle exec ruby main.rb
On GitHub for you to play with it.
Rails usage
As explained in the initialization tutorial, the default Rails template runs on startup:
config/boot.rb
config/application.rb
config/boot.rb contains:
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
which does the require 'bundler/setup' and sets up the require path.
config/application.rb does:
Bundler.require(:default, Rails.env)
which actually requires the gems.
Whenever you specify a Gem in your Gemfile and run bundle install, bundler will go and install specified gem and load code for that Gem in you app by putting require 'whenever' this way bundler will load code for all of your Gems in your Rails app, and you can call any method from any Gem without any pain, like you do most of the time.
but Gems like whenever, faker or capistrano are something which you do not need in your app code you need whenever code in your schedule.rb file to manage crons and capistrano code in deploy.rb file to customize deployment recipe so you need not to load code for these gems in your app code
and wherever you want to call any method from these Gems you can manually require thsese gems by yourself by putting require "whenever" . so you put :require => false in your Gemfile for these Gems, this way bundler will install that Gem but not load code for that Gem itself, you can do it whenever you want by simply putting like require 'whenever' in your case.
Analogy to Explain
## Gemfile
gem "university_degree", require: false
gem "dealing_with_boss"
"dealing_with_boss" - loaded into memory and ready to go.
degree gem - not "needed"....you need to manually require it, in order to use it.
In order to require gems in your Gemfile, you will need to call Bundler.require.
You can prevent bundler from requiring the gem with require: false, but it will still install and maintain the gem. Check this out for a more detailed explanation.

Resources