require lib in rake task - ruby-on-rails

I have a file alert_import in lib/models/alert_import', I would like to use in my task sth like this:
task :send_automate_alerts => :environment do
# STDERR.puts "Path is #{$:}"
Rake.application.rake_require '../../lib/models/alert_import'
ai = AlertImport::Alert.new(2)
ai.send_email_with_notifcations
end
In this code I get error:
Can't find ../../lib/models/alert_import
in AlertImport I have:
module AlertImport
class Alert
def initialize(number_days)
#number_days = number_days
end
def get_all_alerts
alerts = { }
Organization.automate_import.each do |o|
last_import = o.import_histories.where(import_type: "automate").last
last_successful_import = ImportHistory.last_automate_successful_import(o)
if last_import
if last_import.created_at + #number_days.days >= Time.now
alerts[o.id] ="Error during last automate import Last successful import was #{ last_successful_import ? last_successful_import.created_at : "never"}" if last_import.status == "failure"
alerts[o.id] ="Error during last automate import - status pending Last successful import was #{ last_successful_import ? last_successful_import.created_at : "never"}" if last_import.status == "pending"
else
alerts[o.id] = "There were no new files uploaded within #{#number_days} days"
end
else
alerts[o.id] = "The import was never triggered at all"
end
end
alerts
end
def send_email_with_notifcations
alerts =get_all_alerts
unless alerts.empty?
AlertMailer.email_notifications(alerts).deliver
end
end
end
end
The correct solution is:
desc "Send alerts about automate imports"
task :send_automate_alerts => :environment do
require "#{Rails.root}/lib/models/alert_import"
ai = AlertImport::Alert.new(2)
ai.send_email_with_notifcations
end

In Rails 3.x, I've had success by first importing the file using require and then including the module to the namespace. Here's how it would look:
require 'models/alert_import'
namespace :alerts
include AlertImport
desc 'Send alerts about automate imports'
task send_automate_alerts: :environment do
ai = AlertImport::Alert.new(2)
ai.send_email_with_notifcations
end
end

I tried a few options, most notably trying rake require, but it looks like the documentation for rake_require is incorrect. It specifically will not include files that don't end in .rake
So in the end, I did it "from scratch" - something like this:
```
namespace :my_namespace do
task :my_task do
require File.join(Rails.root, 'app', 'services', 'my_module.rb')
class Wrapper
include MyModule
end
Wrapper.new.the_method_I_need(args)
end
end
Done.

Most probably your path wrong, you can do as follow
task :send_automate_alerts => :environment do
# STDERR.puts "Path is #{$:}"
Rake.application.rake_require "#{Rails.root}/lib/models/alert_import"
ai = AlertImport::Alert.new(2)
ai.send_email_with_notifcations
end
"#{Rails.root}" this will give you the current path of your project

Your path is wrong, you can try:
task :send_automate_alerts => :environment do
# STDERR.puts "Path is #{$:}"
Rake.application.rake_require "#{Rails.root}/lib/models/alert_import"
ai = AlertImport::Alert.new(2)
ai.send_email_with_notifcations
end
Regards!

check out there http://rake.rubyforge.org/classes/Rake/Application.html#M000099
define correct path

Related

Writing TestCase for CSV import rake task

I have a simple rails application where I import data from csv into my rails app which is functioning properly, but I have no idea where to start with testing this rake task, as well as where in a modular rails app. Any help would be appreciated. Thanks!
Hint
My Rails structure is a little different from traditional rails structures, as I have written a Modular Rails App. My structure is in the picture below:
engines/csv_importer/lib/tasks/web_import.rake
The rake task that imports from csv..
require 'open-uri'
require 'csv'
namespace :web_import do
desc 'Import users from csv'
task users: :environment do
url = 'http://blablabla.com/content/people.csv'
# I forced encoding so avoid UndefinedConversionError "\xC3" from ASCII-8BIT to UTF-8
csv_string = open(url).read.force_encoding('UTF-8')
counter = 0
duplicate_counter = 0
user = []
CSV.parse(csv_string, headers: true, header_converters: :symbol) do |row|
next unless row[:name].present? && row[:email_address].present?
user = CsvImporter::User.create row.to_h
if user.persisted?
counter += 1
else
duplicate_counter += 1
end
end
p "Email duplicate record: #{user.email_address} - #{user.errors.full_messages.join(',')}" if user.errors.any?
p "Imported #{counter} users, #{duplicate_counter} duplicate rows ain't added in total"
end
end
Mounted csv_importer in my parent structure
This makes the csv_importer engine available in the root of the application.
Rails.application.routes.draw do
mount CsvImporter::Engine => '/', as: 'csv_importer'
end
To correctly migrate in the root of the application, I added initializer
/engines/csv_importer/lib/csv_importer/engine.rb
module CsvImporter
class Engine < ::Rails::Engine
isolate_namespace CsvImporter
# This enables me to be able to correctly migrate the database from the parent application.
initializer :append_migrations do |app|
unless app.root.to_s.match(root.to_s)
config.paths['db/migrate'].expanded.each do |p|
app.config.paths['db/migrate'] << p
end
end
end
end
end
So with this explanation am able to run rails app like every other rails application. I explained this so anyone who will help will understand what to help me with as regards writing test for the rake task inside the engine.
What I have done as regards writing TEST
task import: [:environment] do
desc 'Import CSV file'
task test: :environment do
# CSV.import 'people.csv'
Rake::Task['app:test:db'].invoke
end
end
How do someone write test for a rake task in a modular app? Thanks!
I haven't worked with engines, but is there a way to just put the CSV importing logic into it's own class?
namespace :web_import do
desc 'Import users from csv'
task users: :environment do
WebImport.new(url: 'http://blablabla.com/content/people.csv').call
end
end
class WebImport # (or whatever name you want)
def initialize(url) ... end
def call
counter, CSV parse, etc...
end
end
That way you can bump into the Rails console to do the WebImport and you can also do a test isolating WebImport. When you do Rake tasks and Jobs (Sidekiq etc), you want to make the Rake task act as as thin a wrapper as possible around the actual meat of the code (which is in this case CSV parsing). Separate the "trigger the csv parse" code from the "actually parse the csv" code into their own classes or files.

Use rake namespace as configuration?

I am trying to create a rake file with tasks for consuming my API. I want to be able and pass a lot of arguments to the task, depending on the call to be used. In an effort to make the tasks easier to use, I want the namespace to be part of the configuration. Is this possible?
namespace :myAPI do
SERVER = 'local'
namespace :live do
SERVER = 'live'
end
namespace :beta do
SERVER = 'beta'
end
BASE_URI = {
live: "https://myapi.com/do/v1",
beta: "https://beta.myapi.com/do/v1",
local: "http://127.0.0.1:4500/do/v1"
}
desc 'Get currently logged users'
task :extract_logged_users => :environment do
get("BASE_URI[SERVER]/users/current")
end
}
And then I want to be able and run this against the live server for example:
rake myAPI:live:extract_logged_users
You can create the task in a mor dynamic way like this:
require 'rake'
BASE_URI = {
live: "https://myapi.com/do/v1",
beta: "https://beta.myapi.com/do/v1",
local: "http://127.0.0.1:4500/do/v1"
}.each do |server,url|
namespace :myAPI do
namespace server do |ns|
desc 'Get currently logged users'
task :extract_logged_users do
puts 'get("%s/users/current", %s)' % [server,url]
end
end
end
end
(I replaced your get command with puts to check what happens and added the url into the command).
Now you can call:
rake myAPI:live:extract_logged_users
rake myAPI:beta:extract_logged_users
rake myAPI:local:extract_logged_users
The output:
get("live/users/current", https://myapi.com/do/v1)
get("beta/users/current", https://beta.myapi.com/do/v1)
get("local/users/current", http://127.0.0.1:4500/do/v1)
Alternative coding:
namespace :myAPI do
BASE_URI = {
live: "https://myapi.com/do/v1",
beta: "https://beta.myapi.com/do/v1",
local: "http://127.0.0.1:4500/do/v1"
}
BASE_URI .keys.each do |key|
namespace key do |ns|
desc 'Get currently logged users'
task :extract_logged_users do
puts 'get("%s")' % BASE_URI[key]
end
end
end
end

Is it possible to include modules in rake task and make its methods available for the task in rails app?

In our rails 3.2.12 app, there is a rake task created under lib/tasks. The rake task needs to call a method find_config() which resides in another rails module authentify (module is not under /lib/). Can we include Authentify in rake task and make method find_config() available to call in the rake task?
Here is what we would like to do in the rake task:
include Authentify
config = Authentify::find_config()
Thanks for comments.
require 'modules/module_name'
include ModuleName
namespace :rake_name do
desc "description of rake task"
task example_task: :environment do
result = ModuleName::method_name()
end #end task
end
This works for me. Since your Module is not in /lib you might have to edit how it is required. But it should work. Hope it helps.
PLEASE PAY ATTENTION TO THIS AND SAVE SOME RANDOM HEADACHES!! .
Don't include your module before your namespace:
include YourModule
namespace :your_name do
desc 'Foo'
task foo: :environment do
end
end
or inside your namespace:
namespace :your_name do
include YourModule
desc 'Foo'
task foo: :environment do
end
end
as that will include your module for the whole app and it could bring you a lot of troubles (like me adding in the module some :attr_accessors and breaking factory-bot functioning or other things it has happened in the past for this same reason).
The "no issues" way is inside of your task's scope:
namespace :your_name do
desc 'Foo'
task foo: :environment do
include YourModule
end
end
And yes, if you have multiple tasks, you should include in each of them:
namespace :your_name do
desc 'Foo'
task foo: :environment do
include YourModule
end
desc 'Bar'
task bar: :environment do
include YourModule
end
end
or simply call your method directly if you're only calling a method once in the task:
namespace :your_name do
desc 'Foo'
task foo: :environment do
YourModule.your_method
end
desc 'Bar'
task bar: :environment do
YourModule.your_method
end
end
How to require a Rails service/module in a Rake task?
I had the same problem and manage to solve it by requiring the rails files inside the rake task.
I had a rake task named give_something defined in the file lib/tasks/a_task.rake.
Within that task I needed to call the function give_something from the module AService which lives in the file app/services/a_service.rb
The rake task was defined as follows:
namespace :a_namespace do
desc "give something to a list of users"
task give_something: :environment do
AService.give_something(something, users)
end
end
I was getting the error: uninitialized constant AService
To solve it I had to require the module not at the beginning of the file a_task.rake, but inside the rake task:
namespace :a_namespace do
desc "give something to a list of users"
task give_something: :environment do
require 'services/a_service' # <-- HERE!
AService.give_something(something, users)
end
end
In rails 5.x.x we can do as-
Module file exist her app/lib/module/sub_module.rb like-
module Module
module SubModule
def self.method(params1, params2)
// code goes here...
end
end
end
and my rake_task presented here /lib/tasks/my_tasks.rake as-
namespace :my_tasks do
desc "TODO"
task :task_name => :environment do
Module::SubModule.my_method(params1, params2)
end
end
Note:- the above task file presented in outer lib not in app/lib
Now run the task using following command-
rake my_tasks:task_name
from app directory not from rails console
That worked for me !!!

how to run a function on every task of a namespace with rake command

I want to run a simple function, enter_to_continue on every rake task in a namespace.
currently I add that function at the end of every single task
however, it seems redundant, is there any way to run this function, enter_to_continue, to run at the end of every task of namespace 'mytest' automatically, by doing some meta programming?
namespace :mytest do
task :foo do
system "date"
enter_to_continue
end
task :bar do
system "ls"
enter_to_continue
end
# ...
# Let's say 10 more tasks ends with enter_to_continue comes after
# ...
end
def enter_to_continue
STDIN.gets.chomp
end
You could try Rake::Task#enhance:
require 'rake'
ns = namespace :mytest do
task :foo do |t|
puts "You called task #{t}"
end
task :bar do |t|
puts "You called task #{t}"
end
# ...
# Let's say 10 more tasks ends with enter_to_continue comes after
# ...
end
#
#Add actions to each task (e.g. enter_to_continue)
#
ns.tasks.each{|tsk|
tsk.enhance { puts "\treached method #{__method__}" }
}
#Test the result
task :default => "mytest:foo"
task :default => "mytest:bar"
if $0 == __FILE__
Rake.application[:default].invoke
end
Edit:
You may enhance the tasks also inside the definition block:
namespace :mytest do |ns|
#
#...Task definitions...
#
ns.tasks.each{|tsk|
tsk.enhance { puts "\treached method #{__method__}" }
}
end

uninitialized constant error when run my rake task, why?

I have a class which is NOT an ActiveRecord.
the class is located under lib/room/
lib/room/car_painter.rb
class ROOM::CarPainter
def paint_car
...
end
end
Then, I have a rake task:
under /lib/tasks/
/lib/tasks/new_car_painting.rake
namespace :new_car do
desc "Paint new cars"
task :paint => :environment do
painter = ROOM::CarPainter.new #ERROR HERE- uninitialized constant
painter.paint_car
end
end
When I run rake new_car:paint, I got the error message "uninitialized constant ROOM::CarPainter", Why??
--EDIT---
I also tried to use class function instead of instance function, like following:
class ROOM::CarPainter
def self.paint_car
...
end
end
and
namespace :new_car do
desc "Paint new cars"
task :paint => :environment do
ROOM::CarPainter.paint_car #ERROR HERE- uninitialized constant
end
end
But I get the same error message...why again
This is rake file.
desc 'This is just a testing rake task'
task :update_ts => :environment do |t,args|
puts 'ashish is great'
include TestLib
print_sm
end
This is lib/test_lib.rb file.
module TestLib
def print_sm
puts "Hello World in Lib Directory"
end
end
You just need to include that module.
Edited:
I guess problem is your lib/* folder loading.
Try with this in your application.rb file:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
In rails you need to require from the root and rails 3 practice is the following
require Rails.root.join('path')

Resources