与地理编码器 has_many 和 belongs_to 关联的非常奇怪的结果
Very weird result with geocoder has_many and belongs_to association
我正在使用 Geocoder Gem,它显示有线行为。
我有位置模型
class Location < ActiveRecord::Base
has_many :events
geocoded_by :address
after_validation :geocode
def full_address
"#{postal_code}, #{city}, #{street}"
end
end
和事件模型
class Event < ActiveRecord::Base
belongs_to :location
accepts_nested_attributes_for :location
end
我想查找当前用户位置附近的所有事件。
我尝试按照以下步骤查找附近的位置..
nearby_loc = current_user_location.nearby
它正在返回当前用户位置"locations"附近的所有
然后我试了
nearby_loc.events
但它给我错误
NoMethodError: undefined method `events' for #<ActiveRecord::Relation::ActiveRecord_Relation_Location:0x0000000958c088>
请帮帮我...
events
是在一个位置上定义的,并且
nearby
将为您提供一个位置列表,因此您必须遍历该列表。
简单地说:
all_related_events = []
nearby_locations.includes(:events).each do |location|
all_related_events += location.events
end
如果您的变量名更正确地反映了它们包含的内容,这也会有所帮助,因此请使用 nearby_locations
而不是 nearby_loc
。
[更新]
为了尽量减少查询数量,我添加了 .includes(:events)
,它将在一个查询中获取所有事件。
NoMethodError: undefined method `events' for
ActiveRecord::Relation::ActiveRecord_Relation_Location
您的 nearby_loc
是 ActiveRecord::Relation
,因此 nearby_loc.events
导致错误。您应该遍历 nearby_loc
以使其正常工作。
nearby_loc.each do |n|
n.events
end
我更喜欢从我想要获得的模型开始查询。除了获得 "a collection from collection of collections",您还可以...
将 Location
加入所有事件,以便您可以获取所有 Event
,其 Location
符合特定条件。大多数时候范围只是一堆条件,可以是 merge
d.
像这样:
Event.joins(:location) # Results in `INNER JOIN`
.merge(current_user_location.nearby) # Adds in the conditions for locations
但事情并没有那么简单!
Geocoder 在幕后做了一个非常复杂的 select
,并添加了一些有用的字段,例如 distance
,这些字段取决于输入范围的点。我们不能失去这些,对吧?查询将不再有意义。
一个选项是以非常奇怪的方式执行INNER JOIN
:通过指定FROM
子句从two tables(稍后会详细介绍)并在 WHERE
子句中指定连接条件。为此,我们需要一些 Arel,所以让我们提前获取 tables:
locations = Location.arel_table
events = Event .arel_table # Yeah, call me an indentation maniac
现在有一个问题:我们将使用 current_user_location.nearby
形成的子查询的结果,而不是 locations
table。如何?我们将向 from
提供一系列我们想要使用的东西:
Event.from([current_user_location.nearby.as('locations'), events])
# ^ an array, yeah!
我们这里有:
select events.* from (geocoder subquery) locations, events
现在呢?一个连接条件。正如我所说,由于我们正在创建一个 奇怪的连接 ,我们将在 where
中指定连接条件。我们必须。
Event.from([current_user_location.nearby.as('locations'), events])
.where(location_id: locations[:id])
...这应该可以正常工作。至少完全由数据库完成。
在这种情况下
nearby_loc = current_user_location.nearby
returns 位置列表,而不是单个位置。
要遍历它们并找到每个位置的事件,您可以使用
nearby_events = nearby_loc.map {|loc| loc.events}
但是,就总查询而言,这效率不高。
我正在使用 Geocoder Gem,它显示有线行为。
我有位置模型
class Location < ActiveRecord::Base
has_many :events
geocoded_by :address
after_validation :geocode
def full_address
"#{postal_code}, #{city}, #{street}"
end
end
和事件模型
class Event < ActiveRecord::Base
belongs_to :location
accepts_nested_attributes_for :location
end
我想查找当前用户位置附近的所有事件。
我尝试按照以下步骤查找附近的位置..
nearby_loc = current_user_location.nearby
它正在返回当前用户位置"locations"附近的所有
然后我试了
nearby_loc.events
但它给我错误
NoMethodError: undefined method `events' for #<ActiveRecord::Relation::ActiveRecord_Relation_Location:0x0000000958c088>
请帮帮我...
events
是在一个位置上定义的,并且
nearby
将为您提供一个位置列表,因此您必须遍历该列表。
简单地说:
all_related_events = []
nearby_locations.includes(:events).each do |location|
all_related_events += location.events
end
如果您的变量名更正确地反映了它们包含的内容,这也会有所帮助,因此请使用 nearby_locations
而不是 nearby_loc
。
[更新]
为了尽量减少查询数量,我添加了 .includes(:events)
,它将在一个查询中获取所有事件。
NoMethodError: undefined method `events' for ActiveRecord::Relation::ActiveRecord_Relation_Location
您的 nearby_loc
是 ActiveRecord::Relation
,因此 nearby_loc.events
导致错误。您应该遍历 nearby_loc
以使其正常工作。
nearby_loc.each do |n|
n.events
end
我更喜欢从我想要获得的模型开始查询。除了获得 "a collection from collection of collections",您还可以...
将 Location
加入所有事件,以便您可以获取所有 Event
,其 Location
符合特定条件。大多数时候范围只是一堆条件,可以是 merge
d.
像这样:
Event.joins(:location) # Results in `INNER JOIN`
.merge(current_user_location.nearby) # Adds in the conditions for locations
但事情并没有那么简单!
Geocoder 在幕后做了一个非常复杂的 select
,并添加了一些有用的字段,例如 distance
,这些字段取决于输入范围的点。我们不能失去这些,对吧?查询将不再有意义。
一个选项是以非常奇怪的方式执行INNER JOIN
:通过指定FROM
子句从two tables(稍后会详细介绍)并在 WHERE
子句中指定连接条件。为此,我们需要一些 Arel,所以让我们提前获取 tables:
locations = Location.arel_table
events = Event .arel_table # Yeah, call me an indentation maniac
现在有一个问题:我们将使用 current_user_location.nearby
形成的子查询的结果,而不是 locations
table。如何?我们将向 from
提供一系列我们想要使用的东西:
Event.from([current_user_location.nearby.as('locations'), events])
# ^ an array, yeah!
我们这里有:
select events.* from (geocoder subquery) locations, events
现在呢?一个连接条件。正如我所说,由于我们正在创建一个 奇怪的连接 ,我们将在 where
中指定连接条件。我们必须。
Event.from([current_user_location.nearby.as('locations'), events])
.where(location_id: locations[:id])
...这应该可以正常工作。至少完全由数据库完成。
在这种情况下
nearby_loc = current_user_location.nearby
returns 位置列表,而不是单个位置。
要遍历它们并找到每个位置的事件,您可以使用
nearby_events = nearby_loc.map {|loc| loc.events}
但是,就总查询而言,这效率不高。