我正在尝试首次尝试进行元编程,但这种情况并不顺利!这是一个Rails 4.1应用程序,我正在尝试重构一个活动记录模型(User)来组合两个非常相似的方法。原始方法是稍微复杂的DB调用并按预期工作。
原始代码:
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
答案 0 :(得分:3)
您的方法存在一些问题:
您直接在类上调用twitter_stats_count
,而不是类的实例。因此,该方法需要是类方法。您可以使用
def self.twitter_stats_count(*stats)
# ...
end
此外,您在定义之前调用该方法。在Ruby中,一切(甚至方法定义)都被执行。因此,您只能在定义方法后调用它们。因此,您需要在定义后调用twitter_stats_count
方法。
答案 1 :(得分:2)
看起来很复杂。如果我没有弄错,你可以通过重构代码来减少重复:
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
答案 2 :(得分:1)
twitter_stats_count应该是一个类方法,但你所做的是使它成为一个实例方法,也许你可以试试这个:
# no private here
def self.twitter_stats_count(*status)
#your codes here
end
答案 3 :(得分:0)
您收到此错误的原因是,您已将twitter_stats_count
定义为私有方法,因此您无法在self
上调用此方法。你必须把它放在一个实例方法中,而不是调用它。
检查this.
例如以下给出相同的错误:
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