I'm trying to add a rake task from a gem (geocoder https://github.com/alexreisner/geocoder) from a rake task of my application, as i would like it to be run just after the database is built.
So i have this code inside a rakefile
task :geolocal do
spec = Gem::Specification.find_by_name 'geocoder'
load "#{spec.gem_dir}/lib/tasks/geocoder.rake"
puts '##################GEOCODING##############'
Rake::Task["geocode:all CLASS=ProposedAccomodation"].execute
end
just following this question Ruby Rake load tasks from a gem
but i keep getting the same error
Don't know how to build task 'geocode:all CLASS=ProposedAccomodation'
any clue what i'm doing wrong?
so there are several things to be taken into consideration here.
for the record, this is how you call a task with arguments
Rake::Task["taskname"].execute(args)
in your case, i did not realize first, that it actually uses environment variables instead of task arguments that are read as ENV['CLASS'].
that would answer your question, so you can either set it ENV['CLASS'] = 'ClassName' or pass it along to your call to the rake task rake geolocal CLASS=ProposedAccomodation.
which brings me to a following question: why are you not just calling the original rake task, there is nothing you add to it.
Related
What is the difference between commands rake and rails in Ruby?
Which one is faster and why?
The difference is in what binary is being called.
If you were to call bundle exec which rake within your Rails app root directory, you'd get something like /home/[USERNAME]/.rbenv/versions/2.5.5/bin/rake and for bundle exec which rails, you'd get /home/[USERNAME]/.rbenv/versions/2.5.5/bin/rails. From there you can cat (cat /home/[USERNAME]/.rbenv/versions/2.5.5/bin/rake) both these paths and see similar code is being ran for each, but the end of the files is different.
rails
gem "railties", version
load Gem.bin_path("railties", "rails", version)
rake
gem "rake", version
load Gem.bin_path("rake", "rake", version)
Here they're both calling load on Gem.bin_path but with different arguments, which are attempting to load separate gems in. You can follow the code further by running a irb/pry/rails console, and setting up the needed require 'rubygems' and version = ">= 0.a", then run Gem.bin_path("railties", "rails", version) and Gem.bin_path("rake", "rake", version) to see what the load is actually trying to run. I'll admit it'll become a bit of a rabbit hole before you come across the logic that eventually ends up identifying a rake task argument passed to rails and it proxy's it to Rake and stop there and defer to this SO answer for the rest.
When rails is ran and passed arguments which were intended to be ran by rake, it will attempt to first find if it was an actual argument intended to be given to the rails command, determine that it wasn't, then attempt to run it as a rake command for you for overall naming simplicity added in by the Rails team in Rails v4.
So which is faster to run? rake for actual rake tasks, as it'll bypass the extra logic in needing to determine it was being passed rake arguments. But also rails specific arguments cannot be ran with rake e.g. bundle exec rake generate will not work (unless you have a generate task). If in doubt, run bundle exec rails --help and in at least Rails v5, it'll output which arguments are rails specific and which are rake specific.
rake is a Make-like program implemented in Ruby.
rails is a web framework, which also has some rake tasks.
This means that you can have a ruby program with rake but without rails, but not the other way around.
By itself, rake will be faster because you don't need to load the whole rails application.
But when launching a rake task, it can have dependencies, for example the :environment dependency in a rails app, which tells rake to load the rails environment and quite a bit of your application depending on the current environment.
In this case, the initialization of a rake task may take as long as a rails command.
Please note that the actual task run needs also to be taken into account, it can be very short or take several minutes.
For example, rake db:migrate, which is a rails task available by default, runs the migrations on the database, which can be time-consuming if the database is already populated and/or you have a lot of migrations
I am using Ruby on Rails and have the second_base Gem in use to connect to a second data source. Everything works fine for db:schema:dump commands and everything else; however, I don't see a way to dump the schema from second_base.
When I attempt to run bin/rake db:second_base:schema:dump I get the following message:
rake aborted!
Don't know how to build task 'db:second_base:schema:dump' (see --tasks)
(See full trace by running task with --trace)
When I use the documented db:second_base:schema:cache:dump it does not give me the data I am expecting.
Maybe I'm missing it on the GitHub page, but how would I go about generating a schema.rb file for second_base?
From second_base documentation:
Below is a complete list of :db tasks that automatically run a mirrored
:db:second_base task. Some private or over lapping tasks, like schema
dump/loading or db:setup, are not listed.
So there is no rake task for schema:dump for second_base.
How can I pass arguments to a rake task so that it executes the rake task on a different schema? For example I have rake code such as the one below:
namespace :update_persons_table do
task :import => :environment do
config = Rails.configuration.database_configuration
ActiveRecord::Base.connection.schema_search_path = "my, public, data_master_reports"
# do stuff make updates to table....
end
end
I call this rake task from the command line like this:
RAILS_ENV='production' rake update_persons_table:import
BTW, does the above RAILS_ENV call I am using have to do with the :environment do statement I am using in the second line? Because in my database.yml file i do have a production: database entry. Im trying to figure out how the whole plumbing for this works. This rake task updates a table in a database. But I want to be able to call it on another clone table in a different database. How can I do that with passing parameters in the command line?
How can I pass arguments to a rake task so that it executes the rake task on a different schema?
I think what you are asking is
How can I pass arguments to a rake task so that it executes the rake task on a different environment?
The schema is the same for all environments of your app
does the above RAILS_ENV call I am using have to do with the :environment do statement I am using in the second line?
Yes :environment do will take whatever environment(:development, :test, :production) you are specifying. In your example, its RAILS_ENV='production'
Now to run the rake task in a different environment, like say the development environment
`RAILS_ENV='development' rake update_persons_table:import'
Now the same code that was executed on the production environment db when you ran `RAILS_ENV='production' rake update_persons_table:import' has been run in the development environment db
Hope this is clear enough to get you started
rake --tasks takes about 18s to run. This is just the time it takes to load all the tasks, as a result any task I define will take at least this amount of time to run :
$time rake --tasks
rake db:clean # Cleaning up database
rake passenger:restart # Restart Application
rake spec # Run specs
real 0m18.816s
user 0m7.306s
sys 0m5.665s
My Rakefile :
$: << "."
require "rubygems"
require "rspec/core/rake_task"
desc "Run those specs"
task :spec do
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = %w{--colour --format progress}
t.pattern = 'spec/*_spec.rb'
end
end
task :default => :spec
Any idea why rake takes to much times ?
Thanks
Try spring
Command line will look like:
spring rake -T
It will take more time running the first time, but subsequent runs will be very fast.
This solution worked for me: Faster rake tasks in Rails.
I had to do a little variation where I created a lib/tasks/no_rails directory and put all the Rake files which do not need Rails in there and loaded only those using the above method.
I like the solution Pratik mentions for the general case of loading rails for tasks that need it and not for those that don't, for any rake task without having to remember beforehand.
A less-invasive method to run a rake task that doesn't need rails is to use the -f rake option to tell rake to use a particular Rakefile. This way, rake won't go looking for rake tasks in all of rails.
For example, assuming your task above is in a file called Rakefile at the top level of your project and your Rakefile doesn't do anything that loads Rails like require File.expand_path('../config/application', __FILE__), you can do:
$ rake -f Rakefile spec
and it should run your spec task much faster. Try $ time rake -f Rakefile -T; I did this with a rails-independent Rakefile of mine and got:
real 0m1.543s
user 0m1.308s
sys 0m0.201s
The downside is you have to remember to specify this option every time, and not to specify it if you want to run a rake task from rails like rake db:migrate.
The entire rails environment has to be loaded, therefore even simple rake tasks such as rake --tasks take a while. Opening a console with rails console or script/console takes a similar time. You may try to hack Ruby or Rails to speed up rake, but too much optimization can be bad if you want to switch to a newer version later. Since the rails environment must be loaded, cleaning up routes may also help.
Eventually I would like to get to setting it up as a Rake task and do a cron job, but for right now...all I want to do is take my ruby script that used to work as a standalone script and have it work within my Rails app.
I renamed the file to be .rake instead of .rb and tried doing rake my_script at the command-line, but that gave me this error message:
rake aborted!
Don't know how to build task 'my_script'
(See full trace by running task with --trace)
How do I run this script within my Rails environment?
This is the first time I am doing something like this, so any assistance would be greatly appreciated.
Thanks.
I think what you're looking for is rails runner. I know in Rails 2.3.x you'd do
ruby script/runner <your file>
In Rails 3 it might be slightly different.
http://guides.rubyonrails.org/command_line.html#rails-runner
The primary difference between a runner and a rake task is : runner would boot rails while rake task doesn't (you can tell it to do so).
Since rake can do both (boot/no boot), there's no concept of runner in rails-3 anymore.
So, create a rake task: whatever_name.rake
Example:
desc "This task does awesome stuff"
task :do_awesome_stuff do
awesome_method
end
def awesome_method
#put your ruby code here
end
Now from your command prompt, type rake do_awesome_stuff to execute this rake task.
To make it boot Rails, change task definition to this:
task :do_awesome_stuff => :environment do