繁体   English   中英

Rails / Ruby元编程尝试中的“方法丢失”错误

[英]“method missing” error on Rails/Ruby metaprogramming attempt

我正在尝试首次尝试元编程,但进展并不顺利! 这是一个Rails 4.1应用程序,我正在尝试重构活动记录模型(用户)以结合两种非常相似的方法。 原始方法是稍微复杂的数据库调用,并且可以按预期工作。

原始代码:

  def retweet_count(league)
    celebrity_ids = Roster.
      where("user_id = ? and league_id = ?", self.id, league.id).
      select(:celebrity_id).map { |r| r.celebrity_id }
    Tweet.where({
      tweet_date: league.start_date..league.end_date,
      celebrity_id: celebrity_ids
    }).select(:retweet_count).inject(0) do |sum, n|
      sum + ( n.retweet_count || 0 )
    end
  end

  def favorite_count(league)
    celebrity_ids = Roster.
      where("user_id = ? and league_id = ?", self.id, league.id).
      select(:celebrity_id).map { |r| r.celebrity_id }
    Tweet.where({
      tweet_date: league.start_date..league.end_date,
      celebrity_id: celebrity_ids
    }).select(:favorite_count).inject(0) do |sum, n|
      sum + ( n.favorite_count || 0 )
    end
  end

新代码:

  twitter_stats_count :retweet, :favorite

  private

  def twitter_stats_count(*stats)
    stats.each do |statistic|
      stat = send(statistic).to_s
      define_method "#{stat}_count" do |league|
        celebrity_ids = Roster.
          where("user_id = ? and league_id = ?", self.id, league.id).
          select(:celebrity_id).map { |r| r.celebrity_id }
        Tweet.where({
          tweet_date: league.start_date..league.end_date,
          celebrity_id: celebrity_ids
        }).select("#{stat}_count").inject(0) do |sum, n|
          sum + ( n.send("#{stat}_count") || 0 )
        end
      end
    end
  end

当我尝试启动Rails服务器时,新代码产生错误:

/Users/kiddo/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.rc2/lib/active_record/dynamic_matchers.rb:26:in `method_missing': undefined method `twitter_stats_count' for User (call 'User.connection' to establish a connection):Class (NoMethodError)

我似乎无法弄清楚我在做什么,所以任何指针都将不胜感激!


仅供参考,这是我工作的最终代码。 我主要接受Holger Just的建议,但是结合了其他方面的建议,所以大家都在投票!

  def team_ids(league)
    Roster.where(user_id: self.id, league_id: league.id).pluck(:celebrity_id)
  end

  def self.twitter_stats_count(*stats)
    stats.each do |statistic|
      stat = statistic.to_s
      define_method "#{stat}_count" do |league|
        Tweet.where({
          tweet_date: league.start_date..league.end_date,
          celebrity_id: self.team_ids(league)
        }).sum("#{stat}_count")
      end
    end
  end

  twitter_stats_count :retweet, :favorite

您的方法存在两个问题:

  • 您可以直接在类上调用twitter_stats_count ,而不是类的实例。 这样,该方法必须是一个类方法。 您可以使用以下方法将其定义为类方法

     def self.twitter_stats_count(*stats) # ... end 
  • 此外,在定义方法之前,请先调用该方法。 在Ruby中,所有内容(甚至方法定义)都被执行。 因此,您只能在定义方法后调用它们。 因此,您需要在定义之后将调用放入twitter_stats_count方法。

看起来很复杂。 如果我没记错的话,可以通过重构代码来减少重复:

def retweet_count(league)
  league_tweets(league).sum(:retweet_count)
end

def favorite_count(league)
  league_tweets(league).sum(:favorite_count)
end

def celebrity_ids(league)
  Roster.where(user_id: self.id, league_id: league.id).pluck(:celebrity_id)
end

def league_tweets(league)
  Tweet.where(
    tweet_date: league.start_date..league.end_date,
    celebrity_id: celebrity_ids(league)
  )
end

twitter_stats_count应该是一个类方法,但是您要做的是使其成为实例方法,也许您可​​以尝试以下方法:

# no private here
def self.twitter_stats_count(*status)
    #your codes here
end

之所以会出现此错误,是因为您已将twitter_stats_count定义为私有方法,无法对self调用。 您必须将其放在实例方法中,而不是调用它。

检查一下。

例如下面给出了相同的错误:

class Foo
    baz   

  private
  def baz
    puts "baz called"
  end
end

但是,这将起作用:

class Foo
  def dummy
    baz 
  end


  private
  def baz
    puts "baz called"
  end
end

foo = Foo.new
foo.dummy

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM