Rails:如何在rake任务中定义函数

4
在我的任务文件post.rake中,我想要重复使用一个函数。
  def save_post(title, href, source)
    post = Post.new(title: title, url: href, source: source)
    if post.save
      puts title + 'saved'
    else
      puts title + 'not saved'
    end
  end

然而,当我在这个文件中定义它并重新使用时,它返回的是:
NoMethodError: undefined method `save_post' for main:Object

post.rake 的内容如下:

task :fetch_post => :environment do
  require 'nokogiri'
  require 'open-uri'

  url = 'http://example.com'
  doc = Nokogiri::HTML(open(url) )
  puts doc.css("title").text
  doc.css(".a").each do |item_info|
    title = item_info.text
    href = item_info['href']
    save_post(title, href)
  end

  def save_post(title, href)
    post = Post.new(title: title, url: href)
    if post.save
      puts title + 'saved'
    else
      puts title + 'not saved'
    end
  end
end

内容抓取部分已经可以正常工作。我只是将保存文章的代码移出来,希望将这个方法抽象出来。

我应该把def method放在哪里呢?

3个回答

8
如果在Rake任务中定义方法,则它们将变得全局可访问,这可能会产生不良的副作用。更清晰的方法是使用内联lambda表达式(或将该方法移动到应用程序中的某个类中)。
task :fetch_post => :environment do
  require 'nokogiri'
  require 'open-uri'

  save_post = ->(title, href) {
    post = Post.new(title: title, url: href)
    if post.save
      puts title + 'saved'
    else
      puts title + 'not saved'
    end
  }

  url = 'http://example.com'
  doc = Nokogiri::HTML(open(url) )
  puts doc.css("title").text
  doc.css(".a").each do |item_info|
    title = item_info.text
    href = item_info['href']
    save_post.call(title, href)
  end

end

哦,我错了,这个过程在这个任务之外可用。 - Roman Kiselenko
@Зелёный:嗯?你是什么意思? - Sergio Tulentsev
是的,这是有意的。 - Sergio Tulentsev

4

哦呵呵~~~,函数位置有误,像这样修改即可正常工作:

task :fetch_post => :environment do
  require 'nokogiri'
  require 'open-uri'

  def save_post(title, href)
    post = Post.new(title: title, url: href)
    if post.save
      puts title + 'saved'
    else
      puts title + 'not saved'
    end
  end

  url = 'http://example.com'
  doc = Nokogiri::HTML(open(url) )
  puts doc.css("title").text
  doc.css(".a").each do |item_info|
    title = item_info.text
    href = item_info['href']
    save_post(title, href)
  end
end

此方法仅在此任务中可用。 - Roman Kiselenko
@Зелёный:也许这就是期望的效果。 - Sergio Tulentsev
是的,这样更好。我很抱歉之前没有说过。因为在这个任务中我还重复捕获了其他url,所以这种方法被重复使用。 - ZK Zhao
我只想要一个方便的抽象化,不要太过于严格的面向对象编程。 - ZK Zhao

1
你应该在任务之前和外部定义方法:
task :fetch_post => :environment do
  require 'nokogiri'
  require 'open-uri'

  url = 'http://example.com'
  doc = Nokogiri::HTML(open(url) )
  puts doc.css("title").text
  doc.css(".a").each do |item_info|
    title = item_info.text
    href = item_info['href']
    save_post(title, href)
  end
end

def save_post(title, href)
  post = Post.new(title: title, url: href)
  if post.save
    puts title + 'saved'
  else
    puts title + 'not saved'
  end
end

但我认为这个逻辑应该在模型中。

#app/models/post.rb

class Post < ActiveRecord::Base

  def self.save_post(title, href)
    post = Post.new(title: title, url: href)
    if post.save
      puts title + 'saved'
    else
      puts title + 'not saved'
    end
   end
 end

2
我认为这将把函数放在全局命名空间中。 - Sabrina Leggett
是的,这会将方法放到全局命名空间中,可能会存在风险。 - krebbl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接