Require a file for all db:migrate? - ruby

I'm not sure the "right" way to do this, so I wanted to ask the community. Probably a simple question.
I have a file "dbutils.rb" that I want to automatically include to have available whenever I run a "rake db:migrate", without putting it in application.rb and without putting it in every single db migration.
Where would I put my require to make this happen?

Rails defines $rails_rake_task = true in the :environment task.
The :environment task again is always loaded when you run :migrate (it is loaded for other Rake tasks also). You could use this to add require "dbutils" to your environment.rb when $rails_rake_task is true. And skip loading otherwise.
The other option is a custom Rake task like fl00r suggested.

Related

execute task in .rb file

I'm working on a project that's been in development for quite a while now. I'm trying to figure out how everything works and my next step was how to update/fill the 'library' as it's called in the project.
I found several .rake files hidden away somewhere, but they are used in another .rb file. In said .rb file the entire logic behind the several tasks is set up, so everything happens in the right order.
Now, here's my problem: I need to use the tasks in the .rb file in order to generate the library. They're nested in namespaces and I can't figure out how to reach the tasks.
Here's a shortened version of the structure in the library.rb file:
namespace :library do
task :something do
...
end
...
namespace :local do
...
namespace :generate do
task :default do
...
end
end
end
end
I want to reach the task :default.
Thanks in advance for any help or advice.
EDIT:
The command rake library:local:generate:default gives an error:
rake aborted!
Don't know how to build task 'library:local:generate:default'
EDIT: I can't change the file's names, extentions or locations. Library.rb is currently located in config/deploy/
I'm assuming you would like to run the rake task from the command line, in which case you would enter rake library:local:generate:default.
You also need to require your library.rb file to make the task available. You can do that with the -f flag on the rake command. So, for example: rake -f path/to/library.rb library:local:generate:default.
A fast solution could be rename the file with .rake extension and put the file under lib/task so you can call it with rake namespace:task
namespace :library do
task :something do
...
end
...
namespace :local do
...
namespace :generate do
task default: :environment do
...
end
end
end
end
You forgot to add environment to it. Try the same rake task command again:
rake library:local:generate:default
This might help you

Access default_url_options from rake task

In my application.rb file I have a few options to modify my apps URLs like so:
config.action_controller.default_url_options = { :trailing_slash => true }
But these do not seem to take effect in my Rake tasks, despite the fact that I am running them in the Rails environment via the :environment dependency.
I know that I can get this to work simply by calling the following in my rake task:
default_url_options[:trailing_slash] = true
... but I'd like to DRY this up. Is there a clean way to make a rake task use Rails' default_url_options from application.rb?
You can use the following in a rake task (and in Rails console):
Rails.application.config.action_controller.default_url_options

What is a Rakefile?

I have started learning Ruby and just tried out my first hello world program in NetBeans IDE. I have one doubt, I can see that the new project wizard created set of package structure. It had one "Rakefile" in it. What does that mean and what is the use of it?
It is an alternative to Makefile with Ruby syntax.
I've been using a rake file to manually kick off a call in the code to import various config files.
My rake file "import_contracts.rake" has the following code:
require 'yaml'
task :import_choice_contracts => :environment do
desc 'Import Choice Contracts for Contract Service'
path = "/Users/ernst.r/Desktop/import_contract.yml"
PhiDao::Contract::Service.import_contract_from_file(path)
end
This rake task calls the "import_contract_from_file()" method and passes it the path to a file to import. Once the server is running I use the command "rake import_choice_contracts". Its great for testing my code while I still don't have a GUI frontend to call the completed code in the backend.
Fissh

Testing a rake task in rspec (and cucumber)

I'm new to Ruby, and I've been trying to learn Rake, RSpec, and Cucumber. I found some code that will help me test my Rake tasks, but I'm having trouble getting it to work. I was told here: http://blog.codahale.com/2007/12/20/rake-vs-rspec-fight/ to drop this:
def describe_rake_task(task_name, filename, &block)
require "rake"
describe "Rake task #{task_name}" do
attr_reader :task
before(:all) do
#rake = Rake::Application.new
Rake.application = #rake
load filename
#task = Rake::Task[task_name]
end
after(:all) do
Rake.application = nil
end
def invoke!
for action in task.instance_eval { #actions }
instance_eval(&action)
end
end
instance_eval(&block)
end
end
into my spec_helper.rb file.
I've managed to take this code out and run it in my cucumber steps like this:
When /^I run the update_installers task$/ do
#rake = Rake::Application.new
Rake.application = #rake
load "lib/tasks/rakefile.rb"
#task = Rake::Task["update_installers"]
for action in #task.instance_eval { #actions }
instance_eval(&action)
end
instance_eval(&block)
Rake.application = nil
end
but when I try to get things working in rspec, I get the following error.
ArgumentError in 'Rake task
install_grapevine should install to
the mygrapevine directory'
wrong number of arguments (1 for 2)
/spec/spec_helper.rb: 21:in instance_eval'
/spec/spec_helper.rb: 21:inblock in invoke!'
/spec/spec_helper.rb: 20:in each'
/spec/spec_helper.rb: 20:ininvoke!'
/spec/tasks/rakefile_spec.rb:12:in `block (2 levels) in
'
Unfortunately, I've got just under a week of ruby under by belt, so the metaprogramming stuff is over my head. Could anyone point me in the right direction?
This works for me: (Rails3/ Ruby 1.9.2)
When /^the system does it's automated tasks$/ do
require "rake"
#rake = Rake::Application.new
Rake.application = #rake
Rake.application.rake_require "tasks/cron"
Rake::Task.define_task(:environment)
#rake['cron'].invoke
end
Substitute your rake task name here and also note that your require may be "lib/tasks/cron" if you don't have the lib folder in your load path.
I agree that you should only do minimal work in the Rake task and push the rest to models for ease of testing. That being said I think it's important to ensure that the code is ACTUALLY run in my cron tasks during my integration tests so I think very mild testing of the rake tasks is justified.
Since testing rake is just too much for me, I tend to move this problem around. Whenever I find myself with a long rake task that I want to test, I create a module/class in lib/ and move all the code from the task there. This leaves the task to a single line of Ruby code, that delegates to something more testable (class, module, you name it). The only thing that remains untested is whether the rake task invokes the right line of code (and passes the right parameters), but I think that is OK.
It might be useful to tell us which is the 21nd line of your spec_helper.rb. But given that the approach you posted digs deep in rake (referring to its instance variables), I would entirely abandon it for what I suggested in the previous paragraph.
I've just spent a little while getting cucumber to run a rake task so I thought I'd share my approach. Note: This is using Ruby 2.0.0 and Rake 10.0.4, but I don't think the behaviour has changed since previous versions.
There are two parts to this. The first is easy: with a properly set up instance of Rake::Application then we can access tasks on it by calling #[] (eg rake['data:import']). Once we have a task we can run it by calling #invoke and passing in the arguments (eg rake['data:import'].invoke('path/to/my/file.csv').
The second part is more awkward: properly setting up an instance of Rake::Application to work with. Once we've done require 'rake' we have access to the Rake module. It already has an application instance, available from Rake.application, but it's not yet set up — it doesn't know about any of our rake tasks. It does, however, know where to find our Rakefile, assuming we've used one of the standard file names: rakefile, Rakefile, rakefile.rb or Rakefile.rb.
To load the rakefile we just need to call #load_rakefile on the application, but before we can do that we need to call #handle_options. The call to #handle_options populates options.rakelib with a default value. If options.rakelib is not set then the #load_rakefile method will blow up, as it expects options.rakelib to be enumerable.
Here's the helper I've ended up with:
module RakeHelper
def run_rake_task(task_name, *args)
rake_application[task_name].invoke(*args)
end
def rake_application
require 'rake'
#rake_application ||= Rake.application.tap do |app|
app.handle_options
app.load_rakefile
end
end
end
World(RakeHelper)
Pop that code into a file in features/support/ and then just use run_rake_task in your steps, eg:
When /^I import data from a CSV$/ do
run_rake_task 'data:import', 'path/to/my/file.csv'
end
The behavior might have changed since the correct answer was posted. I was experiencing problems executing two scenarios that needed to run the same rake task (only one was being executed despite me using .execute instead of .invoke). I thought to share my approach to solve the issue (Rails 4.2.5 and Ruby 2.3.0).
I tagged all the scenarios that require rake with #rake and I defined a hook to setup rake only once.
# hooks.rb
Before('#rake') do |scenario|
unless $rake
require 'rake'
Rake.application.rake_require "tasks/daily_digest"
# and require other tasks
Rake::Task.define_task(:environment)
$rake = Rake::Task
end
end
(Using a global variable is suggested here: https://github.com/cucumber/cucumber/wiki/Hooks#running-a-before-hook-only-once)
In the step definition I simply called $rake
# step definition
Then(/^the daily digest task is run$/) do
$rake['collector:daily_digest'].execute
end
Any feedback is welcome.

How can I modify/extend a rake file from another rake file?

I'm trying to find a way to modify/extend a RakeFile from another RakeFile without actually changing it.
When I run my rake task I retrieve a solution from SVN which contains a rakefile. I want to:
Change a variable in this rakefile.
Add a new task to this rakefile
which makes use of existing tasks.
Execute the new task.
I want to do this preferably without actually modifying the original RakeFile on disc.
Here's a way to run arbitrary code prior to executing the task.
your_task = Rake::Task['task:name']
your_task.enhance { this_runs_before_the_task_executes }
You can execute rake tasks similarly.
your_task.invoke
Full docs here.
This is the code which I ended up with to solve the particular problem I was having.
Dir.chdir File.dirname(__FILE__) + '/their_app'
load 'RakeFile'
# Modify stuff from original RakeFile
COMPILE_TARGET = "release"
# Add my task
task :my_task =>[:my_pre_task, :their_task]
I don't know if this is the right way to do it and would appreciate comments/edits if anyone knows a better way.
Thanks to leethal for submitting a answer which helped me on the way and was very useful for another problem I was having.

Resources