Passing a parameter or two to a Rake task - ruby-on-rails

I have a rake task that I want to pass parameters to. For example, I want to issue a command like
<prompt> rake db:do_something 1
and inside the rake task:
...
cust = Customer.find( the_id_passed_in )
# do something with this customer record, etc...
...
Pretty straightforward, right?

The way rake commands accept and define arguments is, well, not pretty.
Call your task this way:
<prompt> rake db:do_something[1,2]
I've added a second parameter to show that you'll need the comma, but omit any spaces.
And define it like this:
task :do_something, :arg1, :arg2 do |t, args|
args.with_defaults(:arg1 => "default_arg1_value", :arg2 => "default_arg2_value")
# args[:arg1] and args[:arg2] contain the arg values, subject to the defaults
end

While passing parameters, it is better option is an input file, can this be a excel a json or whatever you need and from there read the data structure and variables you need from that including the variable name as is the need.
To read a file can have the following structure.
namespace :name_sapace_task do
desc "Description task...."
task :name_task => :environment do
data = ActiveSupport::JSON.decode(File.read(Rails.root+"public/file.json")) if defined?(data)
# and work whit yoour data, example is data["user_id"]
end
end
Example json
{
"name_task": "I'm a task",
"user_id": 389,
"users_assigned": [389,672,524],
"task_id": 3
}
Execution
rake :name_task

Related

Why is `:environment` passed to a rake task as an array?

I am looking at the first line of following rake task:
task :generate_course_group_progress_report => [:environment] do
Why is [:environment] passed as the value of the hash as an array instead of :environment? what does this do? This doesn't seem to break the task.
Is there a scenario where I would pass multiple variables to the hash, i.e [:environment, :something_else]?
No, you can use it also as a symbol.
task test_task: :environment do
# some code
end

Running a 1 time task to enter values into database in Ruby

I have now added a new column to my table in database. I want to add some values to some rows in this new column. I know the logic and all. But actually I dont know the way to add this, or write a 1 time task to do this in ruby on rails. Can any one help me. I just need some idea.
data = Model.where(#your_condition)
if the value is same for all
data.update_all(:new_column => "new value")
if the value is different for all
data.each do |d|
d.update_attributes(:new_column => "some value")
end
You can create a rake task for this, and run it once.
Create a file lib/tasks/my_namespace.rake
namespace :my_namespace do
desc "My Task description"
task :my_task => :environment do
# Code to make db change goes here
end
end
You can invoke the task from the command line in project root folder like
rake my_namespace:my_task RAILS_ENV=production

Rails - Soulmate, export to json one item per line

I'm trying to use Soulmate to make the search and autocompletion. However it requires a json file with all data under a model and one item per line. When I export with to_json i get all object separated by comma.
This is what I want to print:
{"id":1,"term":"Dodger Stadium","score":85,"data":{"url":"\/dodger-stadium-tickets\/","subtitle":"Los Angeles, CA"}}
{"id":28,"term":"Angel Stadium","score":85,"data":{"url":"\/angel-stadium-tickets\/","subtitle":"Anaheim, CA"}}
{"id":30,"term":"Chase Field ","score":85,"data":{"url":"\/chase-field-tickets\/","subtitle":"Phoenix, AZ"}}
{"id":29,"term":"Sun Life Stadium","score":84,"data":{"url":"\/sun-life-stadium-tickets\/","subtitle":"Miami, FL"}}
{"id":2,"term":"Turner Field","score":83,"data":{"url":"\/turner-field-tickets\/","subtitle":"Atlanta, GA"}}
And this is what I print with to_json
[{"id":1,"first_name":"Philip","last_name":"nalle","location":"nallemia","email":"hejsan#hej.com","active":false,"created_at":"2013-06-26T15:00:38.990Z","updated_at":"2013-06-26T15:00:38.990Z"},{"id":2,"first_name":"Philip","last_name":"nalle","location":"hejsan123","email":"hejsan#asd.com","active":false,"created_at":"2013-06-26T15:01:45.905Z","updated_at":"2013-06-26T15:01:45.905Z"},{"id":3,"first_name":"hejsan","last_name":"hejsan","location":"asd","email":"asd#asda.com","active":false,"created_at":"2013-06-26T15:08:20.354Z","updated_at":"2013-06-26T15:08:20.354Z"},{"id":4,"first_name":"well well","last_name":"hello","location":"asd123","email":"asd#asd.com","active":false,"created_at":"2013-06-26T15:10:27.121Z","updated_at":"2013-06-26T15:12:29.991Z"}]
Don't mind the actual data inside the json, I just copied a sample from soulmates readme. This is the rake task.
desc "Save all participants to json"
task :save_to_json => :environment do
File.open("participants.json", "w") { |f| f.write(Participant.all.to_json)}
end
To achieve what you want, you need to output elements one by one.
It will also save memory if instead of .all you grab them by 1000 if there are many of them.
desc "Save all participants to json"
task :save_to_json => :environment do
File.open("participants.json", "w") do |f|
Participant.all.each do |participant|
f.write("#{participant.to_json}\n")
end
end
end

Rake Execute With Multiple Arguments

I'm calling a rake task within a task and I'm running into a roadblock when it comes to calling execute
response = Rake::Task["stuff:sample"].execute[:match => "HELLO"]
or
response = Rake::Task["stuff:sample"].execute[:match => "HELLO",:freq=>'100']
Calling task
task :sample, [:match,:freq] => :environment do |t, args|
The error I get back is 'can't convert Hash into Integer'
Any ideas?
I think the problem is in code you're not posting. Works fine for me:
james#James-Moores-iMac:/tmp$ head r.rb call.rb
==> r.rb <==
task :sample, [:match,:freq] do |t, args|
puts "hello world"
puts args[:match]
end
==> call.rb <==
require 'rubygems'
require 'rake'
load 'r.rb'
Rake::Task["sample"].execute :match => "HELLO"
james#James-Moores-iMac:/tmp$ ruby call.rb
hello world
HELLO
james#James-Moores-iMac:/tmp$
The square brackets in your execute syntax confuse me. Is that a special rake syntax (that you may be using incorrectly) or do you mean to send an array with one element (a hash)?
Isn't it the same as this?
response = Rake::Task["sample"].execute([:match => "HELLO",:freq=>'100'])
Beyond that, Task#execute expects Rake:TaskArguments.
class TaskArguments
...
# Create a TaskArgument object with a list of named arguments
# (given by :names) and a set of associated values (given by
# :values). :parent is the parent argument object.
def initialize(names, values, parent=nil)
You could use:
stuff_args = {:match => "HELLO", :freq => '100' }
Rake::Task["stuff:sample"].execute(Rake::TaskArguments.new(stuff_args.keys, stuff_args.values))
You could also use Task#invoke, which will receive basic args. Make sure you Task#reenable if you invoke it multiple times.
This post is pretty old but I found the first answer is wrong by passing a hash inside an array. We can send arguments by passing them as a hash as following
response = Rake::Task["sample"].execute(match: "HELLO", freq: 100)
Inside the rake task, we can access them in args as args[:match] and args[:freq].to_i

postgresql nextval generating existing values

I had to migrate from a mySql based ruby on rails app to using postgresql. No problems but one so far, and I don't know how to solve it.
The migration of data brought ids along with it, and postgresql is now having problems with existing ids: it's not clear to me where it gets the value that it uses to determine the base for nextval: it certainly isn't the highest value in the column, although you might think that would be a good idea. In any case, it's now colliding with existing id values. id column, created from a standard RoR migration is defined as
not null default nextval('geopoints_id_seq'::regclass)
Is there some place that the value it uses as a base can be hacked? This problem could now arise in any of 20 or so tables: I could use
'select max(id) from <table_name>'
but that seems to make the idea of an autoincrement column pointless.
How is this best handled?
There is a reset_pk_sequences! method on the Postgres adapter. You can call it and it will set it to max(id) + 1, which is probably what you want.
In some projects I get data ETL'ed in often enough to warrant a rake task to do this for all models, or for a specified model. Here's the task - include it in some Rakefile or in it's own under lib/tasks:
desc "Reset all sequences. Run after data imports"
task :reset_sequences, :model_class, :needs => :environment do |t, args|
if args[:model_class]
classes = Array(eval args[:model_class])
else
puts "using all defined active_record models"
classes = []
Dir.glob(RAILS_ROOT + '/app/models/**/*.rb').each { |file| require file }
Object.subclasses_of(ActiveRecord::Base).select { |c|
c.base_class == c}.sort_by(&:name).each do |klass|
classes << klass
end
end
classes.each do |klass|
next if klass == CGI::Session::ActiveRecordStore::Session && ActionController::Base.session_store.to_s !~ /ActiveRecordStore/
puts "reseting sequence on #{klass.table_name}"
ActiveRecord::Base.connection.reset_pk_sequence!(klass.table_name)
end
end
Now you can run this either for all models (defined under RAIS_ROOT/app/models) using rake reset_sequences, or for a specific model by passing in a class name.
The rails 3 version looks like this:
namespace :db do
desc "Reset all sequences. Run after data imports"
task :reset_sequences, :model_class, :needs => :environment do |t, args|
if args[:model_class]
classes = Array(eval args[:model_class])
else
puts "using all defined active_record models"
classes = []
Dir.glob(RAILS_ROOT + '/app/models/**/*.rb').each { |file| require file }
ActiveRecord::Base.subclasses.select { |c|c.base_class == c}.sort_by(&:name).each do |klass|
classes << klass
end
end
classes.each do |klass|
puts "reseting sequence on #{klass.table_name}"
ActiveRecord::Base.connection.reset_pk_sequence!(klass.table_name)
end
end
end
https://gist.github.com/909032
with that definition, the column will get the next value from the geopoints_id_seq sequence.
That sequence is not directly attached to the table. If you're migrating data, you have to create or update that sequence so its starting point is larger than the current max id in your table.
You should be able to set its new value with e.g.
ALTER SEQUENCE geopoints_id_seq RESTART with 1692;
Or whatever select max(id) from table_name; yields
PG uses sequences :
Make it's current value 1 higher than the highest value in your table like this.
SELECT setval('geopoints_id_seq', 999999999, true);
Also see these
http://www.postgresql.org/docs/8.4/interactive/datatype-numeric.html#DATATYPE-SERIAL
http://www.postgresql.org/docs/8.4/interactive/functions-sequence.html
Use setval() to set the starting value for the sequence.

Resources