You*_*suf 2 ruby ruby-on-rails spatial-query
我试图在 Rails 应用程序中使用空间距离,但当我尝试使用 order 方法时,我不断遇到“ActiveRecord::UnknownAttributeReference: 使用非属性参数调用的查询方法”错误。
这是我的代码:
def nearby_locations
third_party_location_query = ThirdPartyLocation.where(id: id).select('geom').to_sql
third_party.organisation.locations.active.
select("locations.*, ROUND(ST_DistanceSphere(locations.geom, (#{third_party_location_query}))::numeric, 0)::integer distance").
order("locations.geom <-> (#{third_party_location_query})").
limit(10).as_json(methods: [:distance])
end
Run Code Online (Sandbox Code Playgroud)
我知道该错误是由于将非属性值传递给 order 方法而引起的,但我不确定在这种情况下如何避免它。如何在查询中使用空间距离而不会遇到此错误?
order从 Rails 6.0 开始,您不能在不传递对象的情况下在语句中使用非列引用Arel。
根据您的情况,选项包括:
order(Arel.sql("locations.geom <-> (#{third_party_location_query})"))
# Or
third_party_location_query = ThirdPartyLocation.select(:geom)
.arel.where(ThirdPartyLocation.arel_table[:id].eq(id))
order(
Arel::Nodes::InfixOperation.new("<->", # operator
Locations.arel_table[:geom], # left side
third_party_location_query) # right side (will add parens as a subquery)
))
Run Code Online (Sandbox Code Playgroud)
我们甚至可以将这部分转换为 arel,但它不会很漂亮
# ROUND(ST_DistanceSphere(locations.geom, (#{third_party_location_query}))::numeric, 0)::integer distance
function = Arel::Nodes::NamedFunction
operation = Arel::Nodes::InfixOperation
operation.new('::',
function.new('ROUND',
[operation.new('::',
function.new('ST_DistanceSphere',[
Location.arel_table[:geom],
ThirdPartyLocation.select(:geom).arel.where(ThirdPartyLocation.arel_table[:id].eq(id))
]),
Arel.sql('numeric')),
0]),
Arel.sql('integer')).as('distance')
Run Code Online (Sandbox Code Playgroud)
对于其他偶然发现这篇文章的人:
请注意,Arel#sql不会执行转义。
如果third_party_location_query需要转义,因为它来自第三方并且可能是危险的,所以可以而且应该使用其他技术来清理这些数据:
例如,如果不需要括号,则:
Arel::Nodes::InfixOperation.new("<->",
Locations.arel_table[:geom],
Arel::Nodes.build_quoted(third_party_location_query))
Run Code Online (Sandbox Code Playgroud)
应该管用。
如果需要括号并且参数是单数或参数以逗号分隔。然后
third_party_location_query = "hello"
Arel::Nodes::Grouping.new([Arel::Nodes.build_quoted(third_party_location_query)]).to_sql
#=> (N'hello')
# Or
third_party_location_query = [1,2,3]
Arel::Nodes::Grouping.new(third_party_location_query ).to_sql
#=> (1,2,3)
Run Code Online (Sandbox Code Playgroud)
根据实现的不同,还有许多其他方法可以处理所需的转义。
| 归档时间: |
|
| 查看次数: |
2016 次 |
| 最近记录: |