How can I set the Devise secret key inside a rake task - ruby-on-rails

I want to run a rake task, but it's complaining about not having the devise secret key. I was hoping defining the task with task :mytask => :environment would have loaded that up for me but I would need to specify it when calling the rake task.
I keep my secret key in .env-production and normally source the file then export DEVISE_SECRET_KEY. But I don't want to have to type source .env-production && export DEVISE_SECRET_KEY && RAILS_ENV=production rake mytask just to run a rake task.
I tried to enhance the :environment task like so:
# lib/tasks/environment.rake
Rake::Task["environment"].enhance do
if Rails.env.production?
fn = ".env-production"
else
fn = ".env"
end
puts "Trying to read devise secret key from #{fn}"
match = File.read(fn).match /DEVISE_SECRET_KEY="(.*)"/
if match
Devise.secret_key = match[1]
ENV['DEVISE_SECRET_KEY'] = match[1]
puts "Found devise secret key"
else
puts "Couldn't find secret key"
end
end
But it still complains about not knowing the key... is there any way to make this work?

Man, the answer was simple.
I just changed it to this:
task :load_devise_key do
if Rails.env.production?
fn = ".env-production"
else
fn = ".env"
end
puts "Trying to read devise secret key from #{fn}"
match = File.read(fn).match /DEVISE_SECRET_KEY='(.*)'/
puts File.read(fn)
if match
Devise.secret_key = match[1]
ENV['DEVISE_SECRET_KEY'] = match[1]
puts "Found devise secret key"
else
puts "Couldn't find secret key"
end
end
task :environment => :load_devise_key
Seems to have done the trick!

Related

IDE Cloud9 - cannot open %=ENV[C9_USER]%: No such file

I run task for importing dates to DB Mysql. After running task rake db:restore displayed error:
cannot open %=ENV[C9_USER]%: No such file
What wrong?
task:
require 'yaml'
namespace :db do
def backup_prep
#directory = File.join(Rails.root, 'db', 'backup')
#db = YAML::load( File.open( File.join(Rails.root, 'config', 'database.yml') ) )[ Rails.env ]
#db_params = "-u #{#db['username']} #{#db['database']}"
#db_params = "-p#{#db['password']} #{#db_params}" unless #db['password'].blank?
end
desc 'Backup database by mysqldump'
task :backup => :environment do
backup_prep
FileUtils.mkdir #directory unless File.exists?(#directory)
file = File.join( #directory, "#{RAILS_ENV}_#{DateTime.now.to_s}.sql" )
command = "mysqldump #{#db_params} | gzip > #{file}.gz" #--opt --skip-add-locks
puts "dumping to #{file}..."
# p command
exec command
end
desc "restore most recent mysqldump (from db/backup/*.sql.*) into the current environment's database."
task :restore => :environment do
unless ENV['RAILS_ENV']=='development'
puts "Are you sure you want to import into #{ENV['RAILS_ENV']}?! [y/N]"
return unless STDIN.gets =~ /^y/i
end
backup_prep
wildcard = File.join( #directory, ENV['FILE'] || "#{ENV['FROM']}*.sql*" )
puts file = `ls -t #{wildcard} | head -1`.chomp # default to file, or most recent ENV['FROM'] or just plain most recent
if file =~ /\.gz(ip)?$/
command = "gunzip < #{file} | mysql #{#db_params}"
else
command = "mysql #{#db_params} < #{file}"
end
p command
puts "please wait, this may take a minute or two..."
exec command
end
end
dump db store in path workspace/db/backup/db.sql

How to parse rake arguments with OptionParser

Reffering that answer I was trying to use OptionParser to parse rake arguments. I simplified example from there and I had to add two ARGV.shift to make it work.
require 'optparse'
namespace :user do |args|
# Fix I hate to have here
puts "ARGV: #{ARGV}"
ARGV.shift
ARGV.shift
puts "ARGV: #{ARGV}"
desc 'Creates user account with given credentials: rake user:create'
# environment is required to have access to Rails models
task :create => :environment do
options = {}
OptionParser.new(args) do |opts|
opts.banner = "Usage: rake user:create [options]"
opts.on("-u", "--user {username}","Username") { |user| options[:user] = user }
end.parse!
puts "user: #{options[:user]}"
exit 0
end
end
This is the output:
$ rake user:create -- -u foo
ARGV: ["user:create", "--", "-u", "foo"]
ARGV: ["-u", "foo"]
user: foo
I assume ARGV.shift is not the way it should be done. I would like to know why it doesn't work without it and how to fix it in a proper way.
You can use the method OptionParser#order! which returns ARGV without the wrong arguments:
options = {}
o = OptionParser.new
o.banner = "Usage: rake user:create [options]"
o.on("-u NAME", "--user NAME") { |username|
options[:user] = username
}
args = o.order!(ARGV) {}
o.parse!(args)
puts "user: #{options[:user]}"
You can pass args like that: $ rake foo:bar -- '--user=john'
I know this does not strictly answer your question, but did you consider using task arguments?
That would free you having to fiddle with OptionParser and ARGV:
namespace :user do |args|
desc 'Creates user account with given credentials: rake user:create'
task :create, [:username] => :environment do |t, args|
# when called with rake user:create[foo],
# args is now {username: 'foo'} and you can access it with args[:username]
end
end
For more info, see this answer here on SO.
Try this:
require 'optparse'
namespace :programs do |args|
desc "Download whatever"
task :download => [:environment] do
# USAGE: rake programs:download -- rm
#-- Setting options $ rake programs:download -- --rm
options = {}
option_parser = OptionParser.new
option_parser.banner = "Usage: rake programs:download -- rm"
option_parser.on("-r", "--rm","Remove s3 files downloaded") do |value|
options[:remove] = value
end
args = option_parser.order!(ARGV) {}
option_parser.parse!(args)
#-- end
# your code here
end
end
You have to put a '=' between -u and foo:
$ rake user:create -- -u=foo
Instead of:
$ rake user:create -- -u foo

How can I read a CSV file as a rake task and instantiate a model class? - getting ActiveRecord connection error

I am writing a Ruby on Rails application which has a Rake task that can parse a CSV file.
Here is the code:
desc "Import Channels into DB\n Usage: rake channel_import"
task :import_channels, :path_to_channel_list do |t, args|
require "#{Rails.root}/app/models/channel"
require "csv"
filePath = args.path_to_channel_list
puts "Filepath received = #{filePath}"
csv = CSV.read("#{filePath}", :encoding => 'windows-1251:utf-8')
csv.each_with_index do |row, i|
if [0].include?(i)
puts "Skipping over row #{i}"
next
end
if(row.nil?)
puts "row[#{i}] was nil"
else
channelName = nil
classif = nil
owner = nil
channelName = row[0].force_encoding('UTF-8')
classif = row[1].force_encoding('UTF-8')
owner = row[2].force_encoding('UTF-8')
if (channelName.nil?)
puts "Channel name for row #{i} was nil"
#add entry to Log file or errors database
next #skip this row of the csv file and go to next row
else
channel_hash = Hash.new("name" =>"#{channelName}", "classification" => "#{classif}", "owner" => "#{owner}" )
end
puts "\nChannel Name = #{channelName}\nClassification = #{classif}\n Ownership = #{owner}"
#If channel name exists in the Database, update it
xisting_channel = nil
xisting_channel = Channel.find_by channel_name: '#{channelName}'
if(xisting_channel.nil?)
#create a new channel
#new_channel = Channel.create(channel_hash)
puts "Inserted....#{#new_channel.inspect}"
else
#update existing channel
Channel.update(xisting_channel.id, :classification => "#{classif}", :ownership => "#{owner}" )
puts "Updated...."
puts "channel_hash = #{channel_hash.inspect} "
end#end if/else
end#end if/else
end #end CSV.each
end
When I run this code I get the following error message:
MRMIOMP0903:am AM$ rake import_channels[/XXXXXXXX/Channellist.csv]
Filepath received = /XXXXXXX/Channellist.csv
Skipping over row 0
Channel Name = APTN HD+
Classification = Specialty
Ownership = Aboriginal Peoples Television Network
rake aborted!
ActiveRecord::ConnectionNotEstablished
I tried to create a Channel object using IRB and it worked just fine. The DB is created and I'm seeing it using MySQL WorkBench. All tables are there, however, I am unable to create the Channel object from the Rake task.
My hypothesis is, perhaps outside of a certain folder/hierarchy the app cannot access the ActiveRecord::Base class or something like this.
Any suggestions on how to make this work?
UPDATE:
BAsed on the answer by Phillip Hallstrom
I changed the top line to load the environment
task :import_channels => :environment do|t, args|
Then tried rake import_channels and got this error:
rake aborted!
undefined method `safe_constantize' for #<Hash:0x007fbeacd89920>
You need to load the environment prior to running your Rake task. I'm not familiar with your multiple task name options there, but for a simple example, you'd want this:
task : import_channels => :environment do

Rails, Create a Task in multiple environment?

I actually have few custom rake tasks.
What I want to do is to create a task that will execute itself on two environments when you simply call it.
I mean, when I run this :
rake initialize_global_settings
I want this to be executed on development and test environment.
Actually I'm constrained doing this :
rake initialize_global_settings (This will be executed in development environment by default, I don't really know why)
and then I do this :
rake initialize_global_settings RAILS_ENV=test
Is it possible to make a task doing both ?
Here's my task :
task :initialize_global_settings => :environment do
puts "Generating all global settings parameters..."
parameters = ["few", "parameters", "here"]
parameters.each do |param|
glob_set = GlobalSetting.new(:field_name => param,
:field_value => "")
if glob_set.save
puts "#{param} created"
else
puts "#{param} already exist"
end
end
puts "done."
end
I found a solution doing this :
task :initialize_global_settings => :environment do
puts "Generating all global settings parameters..."
parameters = ["few", "parameters", "here"]
environments = ['development', 'test']
environments.each do |environment|
Rails.env = environment
puts "\nRunning Task in "+environment+" environment \n\n"
parameters.each do |param|
glob_set = GlobalSetting.new(:field_name => param,
:field_value => "")
if glob_set.save
puts "#{param} created"
else
puts "#{param} already exist"
end
end
puts "\nParameters have been set"
end
end
It works but I've got a conflict between same variables set in test and development environment and I don't know why.

Need to get usernames and passwords from database.yml file and pass into method in rake task

Currently, I am using the pg gem in my rails rake task which is perfect for what I want to do. I create a variable pg_conn and pass in the connection details to the PGconn.connect method. I just don't want to change this rake task everytime the database usernames/ passwords change. How can I pass in the login details from my yaml file to the pg_conn command. Take a look at my code below:
namespace :update_table do
task :import => :environment do
$pg_conn = PGconn.connect(host = "samsi-postgres-90s", port = 6433, options = '', tty ='', dbname = "installs", login = "reports_m", password = "password")
my_query = "select * from all_tables"
conn.query(my_query) do |raw_row|
puts raw_row
end
end
end
Ideally, I would like to pass a hash of credential details to the pg_conn connection variable like so:
$pg_conn = PGconn.connect(yamlfile[:host], yamlfile[:port], '', '', yamlfile[:database], yamlfile[:username], yamlfile[:password])
How can I do this? Thank you for your help!
For Rails3, you can use Rails.configuration in your rake task:
config = Rails.configuration.database_configuration
host = config[Rails.env]["host"]
database = config[Rails.env]["database"]
username = config[Rails.env]["username"]
password = config[Rails.env]["password"]
Just make sure you inherit the environment in your rake task such as
task :users => :environment do
Given this Yaml file:
:host: samsi-postgres-90s
:port: 6433
:database: installs
:username: reports_m
:password: password
you can load it this way:
require 'yaml'
yamlfile = YAML.load(open('your_file_path'))
then you can write:
yamlfile[:host] # => "samsi-postgres-90s"
etc.

Resources