Ruby on rails 4 Rails根据与子模型的关联对结果进行排序';s法

Ruby on rails 4 Rails根据与子模型的关联对结果进行排序';s法,ruby-on-rails-4,Ruby On Rails 4,我有一个事件模型。这个事件模型有一个地址模型。用户模型也有一个地址模型。我想获得未来所有事件的列表,但根据事件地址和用户地址之间的距离进行排序。这个“距离”是我的地址模型上的一个方法。如何使用活动记录编写rails查询?我已经尝试了下面的许多变体,但似乎没有任何效果 Event.where('end_time > ?', Time.now).includes(Address).order(address.distance_from(User.find(3).primary_address)

我有一个事件模型。这个事件模型有一个地址模型。用户模型也有一个地址模型。我想获得未来所有事件的列表,但根据事件地址和用户地址之间的距离进行排序。这个“距离”是我的地址模型上的一个方法。如何使用活动记录编写rails查询?我已经尝试了下面的许多变体,但似乎没有任何效果

Event.where('end_time > ?', Time.now).includes(Address).order(address.distance_from(User.find(3).primary_address))
我总是遇到这样的错误:NameError:未定义的局部变量或main:Object的“address”方法

事件和用户的定义:

class User < ActiveRecord::Base
   # Include default devise modules. Others available are:
   # :confirmable, :lockable, :timeoutable and :omniauthable

   has_many :addresses
   belongs_to :primary_address, :class_name => "Address"


class Event < ActiveRecord::Base
  extend TimeFromPieces

  attr_accessor :start_date_string

  belongs_to :address
  delegate :timezone, to: :address
class用户“地址”
类事件
这是我的地址模型:

class Address < ActiveRecord::Base
  belongs_to :user
  has_many :events

  validates_presence_of :name, :address1, :city, :state, :zip

  geocoded_by :address_as_string do |obj, results|
    Rails.logger.debug { "results: #{results}" }
    obj.lat = results.first.coordinates[0]
    obj.lng = results.first.coordinates[1]
    Rails.logger.debug { "Neighborhoods: #{results.first.address_components_of_type(:neighborhood)}" }
    neighborhoods = results.first.address_components_of_type(:neighborhood)
    if neighborhoods.count > 1
      obj.neighborhood = neighborhoods.first["long_name"]
    end
  end

  after_validation :geocode, :if => :address1_changed?
  after_validation :time_zone_for_address, :if => :address1_changed?

  before_save :set_primary_if_only_address_for_user
  before_save :normalize_fields

  scope :near, ->(lat, lng, distance_in_meters = 2000) {
    where(%{
      ST_Dwithin(
        ST_GeographyFromText(
          'SRID=4326;POINT(' || addresses.lng || ' ' || addresses.lat || ')'
        ),
        ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
        %d
      )
      } % [lng, lat, distance_in_meters])
  }

  def self.distance(address1, address2)
    query = %{ SELECT
      ST_Distance(
        ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
        ST_GeographyFromText('SRID=4326;POINT(%f %f)')
      )
    } % [address1.lng, address1.lat, address2.lng, address2.lat]

    meters = ActiveRecord::Base.connection.execute(query).values.first.first.to_i
    meters/1609.34
  end

  def distance_from(address)
    Address.distance(self, address)
  end
end
类地址1
obj.neighborhood=邻里。第一个[“long_name”]
终止
终止
验证后:地理编码,:if=>:address1\u是否更改?
验证后:地址的时区改变了吗?
保存前:如果只为用户设置主地址,则设置主地址
保存前:规范化\u字段
范围:近、>(纬度,液化天然气,距离单位为米=2000){
其中(%){
圣德维辛(
ST_GeographyFromText(
“SRID=4326;点(“| | addresses.lng | |”“| | addresses.lat |”)”
),
ST_GeographyFromText('SRID=4326;点(%f%f)'),
%d
)
}%[lng、lat、距离(单位:米])
}
def自身距离(地址1、地址2)
查询=%{SELECT
ST_距离(
ST_GeographyFromText('SRID=4326;点(%f%f)'),
ST_GeographyFromText('SRID=4326;点(%f%f)'))
)
}%[address1.lng,address1.lat,address2.lng,address2.lat]
meters=ActiveRecord::Base.connection.execute(query).values.first.first.to_i
米/1609.34
终止
def距离(地址)
地址。距离(自我,地址)
终止
终止

您可以使用gem-like来代替ruby地理编码器,它为active record提供了地理编码功能,它提供了很好的方法,允许您直接按距离查询数据库,因此您不需要获取所有对象来计算其距离

您可以说address是一个可映射的对象,并指向lat和lng字段(如果它们没有使用gem使用的默认名称)

然后,您可以说事件也可以通过附加到它的address对象进行映射

class Event
  acts_as_mappable through: :address
end
这个查询看起来像这样

Event.where('end_time < ?', Time.now).by_distance(origin: address)
Event.where('end_time<?',time.now.)。按距离(原点:地址)

什么是gem提供的
geocoded\u by
?这里需要注意的一点是,您被“rails魔法”愚弄了。如果仔细查看代码的这一部分:.order(address.distance\u from(User.find(3).primary\u address)),您将看到错误的来源。我猜变量地址不在范围内。您也不能像现在这样将ruby代码传递到ActiveRecord方法链中。这可能需要适配器作为SQL查询的一部分执行ruby。那太酷了!正如@MohammadAbuShady在这里指导您的一样,一个通过地理技能扩展AR的宝石是我们的方向。感谢@digidigo指出SQL和RUBY之间的冲突。我将尝试穆罕默德·布沙迪提出的解决方案
Event.where('end_time < ?', Time.now).by_distance(origin: address)