gpt4 book ai didi

ruby-on-rails - 如何将方法添加到 activerecord 集合?

转载 作者:行者123 更新时间:2023-12-03 14:12:48 24 4
gpt4 key购买 nike

我想为特定模型的所有集合添加一个方法。假设我要添加方法 my_complicated_averaging_method到 WeatherData 集合:

WeatherData.all.limit(3).my_complicated_averaging_method()
Station.first.weatherdata.my_complicated_averaging_method()

做这个的最好方式是什么?目前我发现的唯一方法是这样的:
class WeatherData < ActiveRecord::Base
def self.my_complicated_averaging_method
weighted_average = 0
@relation.each do |post|
# do something complicated
# weighted_average =
end
return weighted_average
end
end

这是向集合添加方法的好方法吗?有没有更好/受支持的方法来做到这一点?

最佳答案

有很多方法可以做到这一点,而 Yours 是完全有效的(尽管我个人更喜欢将类方法包装到单独的 block 中检查 this out ),但是随着人们在他们的模型中添加更多的业务逻辑并盲目地遵循“瘦 Controller ,胖模型”的概念,模型变得一团糟。

为了避免这种困惑,引入服务对象是个好主意,在你的情况下,它会是这样的:

class AverageWeatherData
class << self
def data(collection)
new(collection).data
end
end

def initialize(collection)
@collection = collection
end

def data
@collection.reduce do |avg, post|
# reduce goes through every post, each next iteration receives in avg a value of the last line of iteration
# do something with avg and post
end
# no need for explicit return, every line of Ruby code returns it's value
# so this method would return result of the reduce
# more on reduce: http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-reduce
end
end

现在您可以通过将您的集合传递给它来直接调用这个类。但您也可以像这样代理调用:
def self.my_complicated_averaging_method
AverageWeatherData.data(@relation)
end

我鼓励您通过阅读此博客了解更多这种方法:
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

更新

你是对的,使用实例变量是搞乱对象内部结构的一种可能方式(另外它不是公共(public)接口(interface),将来可能会改变)。我这里的建议是使用方法 scoped .基本替换 @relationscoped .

检查这个例子。我使用了我自己项目中的模型来证明它确实有效
2.0.0p247 :001 > Tracking # just asking console to load this class before modifying it
# => Tracking(id: integer, action: string, cookie_id: string, ext_object_id: integer, created_at: datetime, updated_at: datetime)
2.0.0p247 :002 > class Tracking
2.0.0p247 :003?> def self.fetch_ids
2.0.0p247 :004?> scoped.map(&:id)
2.0.0p247 :005?> end
2.0.0p247 :006?> end
# => nil
2.0.0p247 :007 >
2.0.0p247 :008 > Tracking.where(id: (1..100)).fetch_ids
# Tracking Load (2.0ms) SELECT "trackings".* FROM "trackings" WHERE ("trackings"."id" BETWEEN 1 AND 100)
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

更新

在 Rails 4 scoped已弃用,因此使用 all 是正确的.
all.map(&:id)

关于ruby-on-rails - 如何将方法添加到 activerecord 集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19336070/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com