Calling a Rake task from a controller with parameters - ruby-on-rails

I have a instance variable in my controller that queries my table for a value, and I need to send that value through to my rake task.
So here are the 2 relevant lines in my controller:
#turl = Fteam.where(:id => #ids).select(:TeamUrl)
system "rake updateTm:update[#turl]"
Here is my rake file:
desc "Import Players"
task :update, [:Tmurl] => :environment do |t, args|
require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'mechanize'
agent = Mechanize.new
puts "This is the selected Team URL: #{args.Tmurl}"
end
end
This is what the rake task returns:
This is the selected Team URL: #turl
My guess is that the controller is not passing the variable correctly. So how can I pass the actual value of the variable to the rake task so the output is correct?

probably you may need to use interpolation
"rake updateTm:update[#{#turl}]"

It is a .rb file. and and in ruby we can'y call variable directly.
You should use
system "rake updateTm:update[#{#turl}]"

Thanks for all the help and ideas everyone, i came up with a solution.
Instead of #turl = Fteam.where(:id => #ids).select(:TeamUrl)
I changed that to #turl = Fteam.where(:id => #ids).pluck(:TeamUrl)
That gave me the actual value that i needed rather then the active record, which was causing the error because it could not pass a value for which it could not translate or understand.

Related

Rails dynamically create model and use it

I am creating a model whose name is the input argument in a rake task. After the rake task, I wish to use the model to insert data.
So for example, I call my rake task with input Apple and the model Apple is created. Then I wish to do Apple.insert_all([{name: x},{name: y}...]) in another rake task but I get NameError: uninitialized constant Apple
Here's a better picture of the flow of what I'm doing
Rake::Task["create:fruit"].invoke("Apple") # create model here
Rake::Task["create:insert"].invoke("Apple") # insert data here but getting error
This is how I process the input in the second rake task:
task :insert, [:name] do |t, args|
fruit = args.name
fruit.classify.constantize.insert_all(xxx)
end
Any suggestions for how to go about this?
I created a new project and tried your code. I think the problem is in this line
fruit.classify.constantize.insert_all(xxx)
The code bellow works and create new records. I use a simple rake command to run it.
create.rake file
namespace :create do
desc "TODO"
task :insert, [:name] do |t, args|
klass = Object.const_get(args.name)
klass.create([{name: 'x'},{name: 'y'}])
p klass.count # testing new records have been saved
end
end
Rakefile file
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
task :default do
Rake::Task["create:insert"].invoke("Apple")
end

Rake Task environment variable w/Command Line Arguments

So I was getting some "Uninitalized constants" on my rake task, and I did some googling and found that the environment variable needed to be loaded in. However im also using a command line argument and im not sure if the positioning is correct or what:
desc "Wipes Specific User"
task :clean_user => environment [:user] do |t, args|
puts "Running clean_user for #{args[:user]}..."
Core::Stuff.find(args[:user]).wipe_user
end
Without the environment variable somewhere I get complains about Core::Stuff being uninitialized, but Im trying to pass :user via CL. (This is just a sample rake task to make sure stuff works).
Am I missing something?
edit: Fixing the issue with:
task :clean_user, [:user] => :environment however now it seems to be loading my PATH into the argument (I get an error complaining how "Core::Stuff cannot find a user id with id of "" . So it's like it's using my CL path as the ID?
The docs in the gem specify:
task task_name, arguments => dependencies
That means your code needs to be:
task :clean_user, [:user] => :environment do |t, args|

testing rake tasks with Rspec is not accepting arguments

I am trying to write a Rspec test for one of my rake task, according to this post by Stephen Hagemann.
lib/tasks/retry.rake:
namespace :retry do
task :message, [:message_id] => [:environment] do |t, args|
TextMessage.new.resend!(args[:message_id])
end
end
spec/tasks/retry_spec.rb:
require 'rails_helper'
require 'rake'
describe 'retry namespace rake task' do
describe 'retry:message' do
before do
load File.expand_path("../../../lib/tasks/retry.rake", __FILE__)
Rake::Task.define_task(:environment)
end
it 'should call the resend action on the message with the specified message_id' do
message_id = "5"
expect_any_instance_of(TextMessage).to receive(:resend!).with message_id
Rake::Task["retry:message[#{message_id}]"].invoke
end
end
end
However, when I run this test, I am getting the following error:
Don't know how to build task 'retry:message[5]'
On the other hand, when I run the task with no argument as:
Rake::Task["retry:message"].invoke
I am able to get the rake task invoked, but the test fails as there is no message_id.
What is wrong with the way I'm passing in the argument into the rake task?
Thanks for all help.
So, according to this and this, the following are some ways of calling rake tasks with arguments:
Rake.application.invoke_task("my_task[arguments]")
or
Rake::Task["my_task"].invoke(arguments)
On the other hand, I was calling the task as:
Rake::Task["my_task[arguments]"].invoke
Which was a Mis combination of the above two methods.
A big thank you to Jason for his contribution and suggestion.
In my opinion, rake tasks shouldn't do things, they should only call things. I never write specs for my rake tasks, only the things they call.
Since your rake task appears to be a one-liner (as rake tasks should be, IMO), I wouldn't write a spec for it. If it were more than one line, I would move that code somewhere else to make it a one-liner.
But if you insist on writing a spec, maybe try this: Rake::Task["'retry:message[5]'"].invoke (added single quotes).

rails mechanize run through each url in a postgres table

*Edit:
Per my comment below, I guess a better question would be, 'What would the proper way be to have mechanize go through each url and update its name column? (each name would be unique to the url)' Below is what I've been basing my exercise on. *
I have a postgres table that goes like...
| name (string) | url (text) |
The url column is already populated with various url's and appears like this one:
http://www.a4apps.com/Websites/SampleCalendar/tabid/89/ctl/Register/Default.aspx
I am trying to run a mechanize rake task that will run through each url and update the name based on the text it finds at a css tag.
namespace :db do
desc "Fetch css from db urls"
task :fetch_css => :environment do
require 'rubygems'
require 'mechanize'
require 'open-uri'
agent = Mechanize.new
url = Mytable.pluck(:url)
agent.get(url)
agent.page.search('#dnn_ctr444_ContentPane').each do |item|
name = item.css('.EventNextPrev:nth-child(1) a').text
Mytable.update(:name => name)
end
end
end
When I run the rake task it returns:
rake aborted!
bad URI(is not URI?): %255B%2522http://www.a4apps.com/Websites/SampleCalendar/tabid/89/Default.aspx%2522,%2520%2522http://www.a4apps.com/Websites/SampleCalendar/tabid/89/ctl/Privacy/Default.aspx%2522,%2520%2522http://www.a4apps.com/Websites/SampleCalendar/tabid/89/ctl/Terms/Default.aspx%2522,%2520%2522http://www.a4apps.com/Websites/SampleCalendar/tabid/89/ctl/Register/Default.aspx%2522%255D
Thanks for any help. If there's any way I can make the question easier to answer, please let me know.
Mike
I feel a little lonely answering my own questions lately but I'll post my answers in the event that someone else finds themselves in the same bind. Also, maybe others will tell me if my solution has any fatal flaws that I am not seeing yet. Here is my final rake that seems to be working, getting urls from my table, running mechanize on them and updating the table with the info found at the urls...
namespace :db do
desc "Fetch css from db urls"
task :fetch_css => :environment do
Mytable.all.each do |info| # for each row do...
require 'rubygems'
require 'mechanize'
require 'open-uri'
agent = Mechanize.new
agent.get(info.url) # get the url column data for the current db row...
nombre = agent.page.search('.EventNextPrev:nth-child(1) a').text # plug it into mech.
info.update_attributes(:name => nombre) # and update the db with the css result.
end
end
end
Thanks.
Mike

How do I access one of my models from within a ruby script in the /lib/ folder in my Rails 3 app?

I tried putting my script in a class that inherited from my model, like so:
class ScriptName < MyModel
But when I ran rake my_script at the command-line, I got this error:
rake aborted!
uninitialized constant MyModel
What am I doing wrong?
Also, should I name my file my_script.rb or my_script.rake?
Just require the file. I do this in one of my rake tasks (which I name my_script.rake)
require "#{Rails.root.to_s}/app/models/my_model.rb"
Here's a full example
# lib/tasks/my_script.rake
require "#{Rails.root.to_s}/app/models/video.rb"
class Vid2 < Video
def self.say_hello
"Hello I am vid2"
end
end
namespace :stuff do
desc "hello"
task :hello => :environment do
puts "saying hello..."
puts Vid2.say_hello
puts "Finished!"
end
end
But a better design is to have the rake task simply call a helper method. The benefits are that it's easier to scan the available rake tasks, easier to debug, and the code the rake task runs becomes very testable. You could add a rake_helper_spec.rb file for example.
# /lib/rake_helper.rb
class Vid2 < Video
def self.say_hello
"Hello I am vid2"
end
end
# lib/tasks/myscript.rake
namespace :stuff do
desc "hello"
task :hello => :environment do
Vid2.say_hello
end
end
All I had to do to get this to work was put my requires above the task specification, and then just declare the :environment flag like so:
task :my_script => :environment do
#some code here
end
Just by doing that, gave me access to all my models. I didn't need to require 'active_record' or even require my model.
Just specified environment and all my models were accessible.
I was also having a problem with Nokogiri, all I did was removed it from the top of my file as a require and added it to my Gemfile.

Resources