我有一个活动记录,我有一个用例:我想在map
ActiveRecord
中使用scopes
。以下是我的代码:
class SupportedGeoIdAndLocation < ActiveRecord::Base
scope :supported_geo_ids, lambda { all.map(&:geo_id).uniq }
# also tried: scope :supported_geo_ids, lambda { select('distinct geo_id').map(&:geo_id).uniq }
scope :locations_for_geo_id, lambda { |geo_id| where(:geo_id => geo_id).map(&:location) }
end
但当我SupportedGeoIdAndLocation.supported_geo_ids
时,我得到空数组,而SupportedGeoIdAndLocation.all.map(&:geo_id).uniq
给出了我想要的结果。
我正在寻找一种方法,以便可以一次性使用lambda完成,而不是通过链接不同的方法并完全避免类函数。
看起来我正在以错误的方式使用示波器,请建议我可以采用哪种方法。
版本:padrino
:0.10.5,ruby
:ruby-1.9.3-p429,ActiveRecord
:3.1.6
答案 0 :(得分:5)
scope
应返回ActiveRecord::Relation
,因此范围可以与其他范围或类方法等链接。
如果你想获得一个数组,请改用class方法。
def self.supported_geo_ids
all.map(&:geo_id).uniq
end
答案 1 :(得分:3)
在我的一个模型中使用了一些类似的代码后,我终于找到this question(因为我得到了相同的错误消息(在Rails 3.2中))。接受的答案指出ActiveRecord
隐含地假定scopes
是&#34;可链接的&#34; (在ARel
意义上)你返回的数组显然不是。
因此,虽然您可以在类方法中执行任何您想要的操作(如@xdazz的答案),但如果您坚持使用ActiveRecord
,则必须遵守scope
约定(乍一看只是用你提供的lambda
来定义一个类方法。似乎还有比我能发现的更多。
<强>更新强>
经过一些更多的摆弄后,我觉得我得到了尽可能接近。您可以编写一个只返回支持的地理ID的scope
,如下所示:
class SupportedGeoIdAndLocation < ActiveRecord::Base
scope :supported_geo_ids, lambda { select("distinct(geo_id)") }
end
然而,这将返回一个ARel
关系,该关系可以转换为只有SupportedGeoIdAndLocation
属性集的geo_id
个对象数组(抱歉让您失望, 是一个类方法,即使它最终是通过scope
类方法定义的。因此,如果你需要一个属性数组,你可以使用你在另一个类方法中提出的方法将它变成一个:
class SupportedGeoIdAndLocation < ActiveRecord::Base
def self.geo_ids_array
supported_geo_ids.map(&:geo_id)
end
end
请注意,现在无需致电uniq
,因为distinct
中的scope
已对此进行了处理。从rails 4.0.2开始ActiveRecord
确实支持distinct
方法,因此如果您可以更新ActiveRecord
gem,则不必使用字符串Padrino
不应该依赖它。
答案 2 :(得分:3)
正如@patru指出的那样,范围只是为了返回关系。它们并不意味着返回价值。因此,您的问题&#34;如何使范围返回特定值?&#34;无法回答。
我的印象是你觉得类方法设计不好,或者没有&#34; The Rails Way&#34;,但在这种情况下,我同意@xdazz他们是最好的解决方案。
但是,我会稍微改变一下这个方法:
def self.supported_geo_ids
self.all(:select => "DISTINCT(geo_id)").map(&:geo_id)
end
这样,在数据库引擎中执行重复数据删除,并且仅返回所需的值。这使得查询可能更快。
在较新版本的Rails中,您可以这样写:
def self.supported_geo_ids
self.uniq.pluck(:geo_id)
end
如果由于某种原因你仍然不想使用课堂方法,请解释原因,我会尝试考虑解决方法。