【问题标题】:Rails: How to define a function in a rake taskRails:如何在 rake 任务中定义函数
【发布时间】:2014-09-28 09:21:50
【问题描述】:

在我的任务文件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放在哪里?

【问题讨论】:

    标签: ruby-on-rails ruby rake


    【解决方案1】:

    如果您在 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
    

    【讨论】:

    • 我错了,这个过程在这个任务之外可用
    • @Зелёный:嗯?什么意思?
    • 是的,这是故意的。
    【解决方案2】:

    OOOH~~~,函数位置错了,像这样,有效:

    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
    

    【讨论】:

    • 此方法仅在此任务中可用。
    • @Зелёный:也许这就是我们想要的效果。
    • 是的,这样更好。我很抱歉我之前没有这么说。因为我也在此任务中重复捕获其他 url。这就是这个方法被重用的方式
    • 我只想要一个方便的抽象。不是太严格的面向对象编程。
    【解决方案3】:

    您应该在任务之前和之外定义方法:

    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
    

    【讨论】:

    • 我认为将函数放在全局命名空间中
    猜你喜欢
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 2011-08-04
    • 2016-03-23
    • 2011-06-12
    • 1970-01-01
    相关资源
    最近更新 更多