如何在Rails环境中将参数传递给Rake任务?

Wil*_*ill 210 ruby rake ruby-on-rails

我能够传递如下参数:

desc "Testing args"
task: :hello, :user, :message do |t, args|
  args.with_defaults(:message => "Thanks for logging on")
  puts "Hello #{args[:user]}. #{:message}"
end
Run Code Online (Sandbox Code Playgroud)

我还能够为Rails应用程序加载当前环境

desc "Testing environment"
task: :hello => :environment do 
  puts "Hello #{User.first.name}."
end
Run Code Online (Sandbox Code Playgroud)

我想做的是能够拥有变量和环境

desc "Testing environment and variables"
task: :hello => :environment, :message do |t, args|
  args.with_defaults(:message => "Thanks for logging on")
  puts "Hello #{User.first.name}. #{:message}"
end
Run Code Online (Sandbox Code Playgroud)

但这不是一个有效的任务调用.有谁知道我怎么能做到这一点?

ing*_*ger 370

只是为了跟进这个老话题; 这就是我认为当前的Rakefile(很久以前)应该在那里做的事情.这是当前获奖答案(hgimenez)的升级和修复版本:

desc "Testing environment and variables"
task :hello, [:message]  => :environment  do |t, args|
  args.with_defaults(:message => "Thanks for logging on")
  puts "Hello #{User.first.name}. #{args.message}"   # Q&A above had a typo here : #{:message}
end
Run Code Online (Sandbox Code Playgroud)

这就是你调用它的方式(http://guides.rubyonrails.org/v4.2/command_line.html#rake):

  rake "hello[World]" 
Run Code Online (Sandbox Code Playgroud)

对于多个参数,只需在任务声明(task :hello, [:a,:b,:c]...)的数组中添加它们的关键字,并以逗号分隔:

  rake "hello[Earth,Mars,Sun,Pluto]" 
Run Code Online (Sandbox Code Playgroud)

注意:未检查参数的数量,因此遗漏了奇数行星:)

  • 这个答案应该是公认的答案. (38认同)
  • 男人......耙子对我来说总是感觉如此无瑕疵.红宝石中的大多数东西你的第一个猜测是它的实际工作方式.这种语法很奇怪.</咆哮> (31认同)
  • 要发送2个参数,task:hello,[:arg1,:arg2] =>:environment do | t,args | (4认同)
  • 发送2个参数,[:arg1,:arg2]之间没有空格 (2认同)
  • @hbin啊所以这就是你调用rake而不是Rakefile中的声明(ChaseT.的评论引用)..是的,在那种情况下是shell规则,所以你要把东西写成一个shell-word(没有空格) )或引用空格,或在整个事物周围使用引号,例如`rake'webp:convert ["hello","world"]'`..警告:我现在没有尝试过这个,但它应该有效. (2认同)

hgm*_*mnz 114

TLDR;

task :t, [args] => [deps] 
Run Code Online (Sandbox Code Playgroud)

原始答案

将参数传递给rake任务时,可以使用:needs选项来请求环境.例如:


desc "Testing environment and variables"
task :hello, :message, :needs => :environment do |t, args|
  args.with_defaults(:message => "Thanks for logging on")
  puts "Hello #{User.first.name}. #{args.message}"
end
Run Code Online (Sandbox Code Playgroud)

根据@ Peiniau的评论更新如下

至于Rails> 3.1

task :t, arg, :needs => [deps] # deprecated
Run Code Online (Sandbox Code Playgroud)

请用

task :t, [args] => [deps] 
Run Code Online (Sandbox Code Playgroud)

  • 对于Rails 3.1'任务:t,arg,:needs => [deps]'已弃用.请改用'task:t,[args] => [deps]'. (53认同)
  • 为了用一个例子来澄清之前的评论,我相信这可以解决`task:hello,[:message] => [:environment] do | t,args |`. (23认同)
  • 请注意,最新的文档以这种方式描述`:needs`方法:"该格式仍然支持兼容性,但不建议使用它." (我仅在未来的浏览器中提到这一点,因为它表明最终将不再支持`:needs`.该部分称为"弃用的任务参数格式"...) (13认同)
  • 另外澄清:传递多个参数,`task:hello,[:message1,:message2] => [:environment] do | t,args |`工作,并调用使用`rake hello ['message#1','消息#2']`.警告:如果参数列表包含任何明文,我发现rake会失败,例如`rake hello ['message#1','message#2']`(注意逗号后面的空格). (12认同)
  • 该代码中的错误:放置"Hello#{User.first.name}.#{:message}"...这不打印"感谢您登录",只是"消息".修复:#{args.message}为最后一个替换. (6认同)

mik*_*ter 59

为了完整起见,这里是上面提到的文档中的示例:

   task :name, [:first_name, :last_name] => [:pre_name] do |t, args|
     args.with_defaults(:first_name => "John", :last_name => "Dough")
     puts "First name is #{args.first_name}"
     puts "Last  name is #{args.last_name}"
   end
Run Code Online (Sandbox Code Playgroud)

笔记:

  • #with_defaults显然,你可以省略这个电话.
  • 你必须使用an Array作为你的论据,即使只有一个.
  • 先决条件不需要是Array.
  • args是一个实例Rake::TaskArguments.
  • t是一个实例Rake::Task.

  • 这解释了为什么`args.empty?`给了我奇怪的结果.`args`看起来像一个哈希,但它是一个`Rake :: TaskArguments`.因此,如果在没有args传递时需要特殊行为,请在检查`args`是否为空之前调用`#to_hash`或`#to_s`. (3认同)

Dog*_*her 20

另一种方法:使用OS环境变量.这种方法的好处:

  • 所有依赖的rake任务都可以获得选项.
  • 语法要简单得多,不依赖于很难弄清楚并随时间变化的rake DSL.

我有一个rake任务,需要三个命令行选项.这是我如何调用它:

$ rake eaternet:import country=us region=or agency=multco
Run Code Online (Sandbox Code Playgroud)

这是非常干净,简单,只是bash语法,我喜欢.这是我的佣金任务.也非常干净,没有魔力:

task import: [:environment] do
  agency = agency_to_import
  puts "Importing data for #{agency}..."
  agency.import_businesses
end

def agency_to_import
  country_code = ENV['country'] or raise "No country specified"
  region_slug  = ENV['region']  or raise "No region specified"
  agency_slug  = ENV['agency']  or raise "No agency specified"
  Agency.from_slugs(country_code, region_slug, agency_slug)
end
Run Code Online (Sandbox Code Playgroud)

此特定示例未显示依赖项的使用.但如果:import任务确实依赖于其他人,他们也可以访问这些选项.但是使用普通的rake选项方法,他们不会.


Lon*_*hus 11

虽然这些解决方案有效,但在我看来这太复杂了.

另外,如果你在zsh中这样做,如果你的数组中的括号没有用'\'转义,你就会出错.

我建议使用ARGV数组,它工作正常,更简单,并且不容易出错.例如:

namespace :my_example do
  desc "Something"
  task :my_task => :environment do
    puts ARGV.inspect
  end
end
Run Code Online (Sandbox Code Playgroud)

然后

rake my_example:my_task 1 2 3

#=>  ["my_example:my_task", "1", "2", "3"]
Run Code Online (Sandbox Code Playgroud)

您唯一需要记住的是ARGV [0]是进程名称,因此只使用ARGV [1 ..- 1].

我意识到严格来说这并没有回答这个问题,因为它没有利用:环境作为解决方案的一部分.但是OP没有说明为什么他包含这个规定所以它可能仍然适用于他的用例.

  • 加载Rails应用程序代码需要`:environment`.在Rails应用程序上尝试它我得到:`["my_example:my_task","1","2","3"] rake aborted!不知道如何构建任务'1'(参见--tasks)` (2认同)