ActiveRecord通过自定义方法进行范围设定

时间:2014-01-02 23:01:58

标签: ruby-on-rails ruby activerecord postgis rgeo

所以,假设我有一个名为Property的类,我正在使用PostGIS适配器来跟踪物理属性(如房子,办公室等)之间的空间关系。我也在使用RGeo gem来保持跟踪个别物业的位置。

因此,如果我打电话:

p = Property.first
p.location # => #<RGeo::Geographic::ProjectedPointImpl:0x3f9303eecc3c "POINT (-111.67226 33.231371)">
p.location.latitude # => 33.231371

我在Property模型中也有一个自定义方法:

class Property < ActiveRecord::Base
  ...
  def lat
    self[:location].latitude
  end
end

p.lat # => 33.231371

我想创建一个范围,例如“纬度小于x”或“经度大于x”。

但是,如果我输入控制台

irb> Property.where("lat > ?", 30)
# => ActiveRecord::StatementInvalid: PG::Error: ERROR:  column "lat" does not exist

如果我尝试的范围看起来像:

class Property < ActiveRecord::Base
  ...
  scope :lat_lt, lambda {|val| where(['properties.location.latitude <= ?', val]) }
end

然后我得到

irb> Property.lat_lt "30"
# => Property Load (1.3ms)  SELECT "properties".* FROM "properties" WHERE (properties.location.latitude <= '30')
# => ActiveRecord::StatementInvalid: PG::Error: ERROR:  schema "properties" does not exist

所以基本上,没有“lat”列,虽然我可以在Property实例上调用.lat并获取我需要的信息。现在我只需要能够通过返回值创建一种范围,即使没有列。

我想了解更多有关其如何运作的信息; ActiveRecord查询操作的级别是不知道在模型上定义的方法,在数据库中不存在的方法?

非常感谢任何和所有帮助。

1 个答案:

答案 0 :(得分:1)

当您使用where方法(或AR查询接口的任何其他方法:http://guides.rubyonrails.org/active_record_querying.html)时,您正在构建一个在需要时执行的SQL查询。由于您的数据库无法访问您的代码,因此它不知道您已定义的方法 - 它只能访问存储在数据库中的内容。

如果您想根据自定义方法获得结果,可以 1.获取所有属性的列表,然后使用select方法(http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-select)过滤它们 - 但这可能会遇到相当严重的性能和资源问题。 2.(推荐)弄清楚如何使用纯sql获得你想要的东西。

如果您可以显示位置在db中的存储方式,我会尝试进一步提供帮助。