我正在尝试找到Order' pickup_address'距离内的所有驱动程序,如GeoKit指南中所述https://github.com/geokit/geokit-rails#using-through
驱动程序通过UserLocations拥有位置,订单通过PickupAddresses具有位置。
我收到以下错误:
NoMethodError in OrdersController#show
undefined method `lat' for "Order"
Order.rb
class Order < ApplicationRecord
has_paper_trail
# an order MUST contain the following
validates_presence_of :description
validates_presence_of :weight
validates_presence_of :length
validates_presence_of :width
validates_presence_of :height
validates_presence_of :pickup_address
validates_presence_of :dropoff_address
validates_presence_of :pickup_contact
validates_presence_of :dropoff_contact
# each order should have one address for pickup and one address for dropoff
has_one :pickup_address, :as => :locatable # also works for belongs_to associations
acts_as_mappable :through => :pickup_address
has_one :dropoff_address, inverse_of: :order
# each order needs two contacts
has_one :pickup_contact, inverse_of: :order
has_one :dropoff_contact, inverse_of: :order
end
PickupAddress.rb
class PickupAddress < Address
belongs_to :locatable, :polymorphic => true
acts_as_mappable
end
我还将acts_as_mappable添加到Address.rb以查看代码是否可行,但没有任何更改。
class Address < ApplicationRecord
belongs_to :locatable, :polymorphic => true
acts_as_mappable
# Attributes to have a valid address for Driver/Geocoder
validates_presence_of :street1
validates_presence_of :city
validates_presence_of :state
validates_presence_of :country
validates_presence_of :postal
validates_presence_of :type
# Geocoder conversion for easier calculations
geocoded_by :full_address
after_validation :geocode
# address used by Geocoder and condensed display
def full_address
[street1, city, state, country].compact.join(', ')
end
end
这是我收到错误的行:
@drivers = Driver.within(5, :origin => @order)
并且,作为参考,这是我的驱动程序映射:
Driver.rb
class Driver < User
has_many :orders
end
User.rb
class User < ApplicationRecord
# each user has a location, drivers first, then can expand later
has_one :user_location, :as => :locatable
acts_as_mappable :through => :user_location
end
UserLocation.rb
class UserLocation < ApplicationRecord
belongs_to :locatable, :polymorphic => true
acts_as_mappable :default_units => :miles
#reverse_geocoded_by :latitude, :longitude
end
最后,架构:
create_table "user_locations", force: :cascade do |t|
t.integer "user_id"
t.float "lat"
t.float "lng"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_user_locations_on_user_id", using: :btree
end
create_table "addresses", force: :cascade do |t|
t.string "type"
t.string "street1"
t.string "street2"
t.string "city"
t.string "state"
t.string "postal"
t.string "country"
t.integer "order_id"
t.float "lat"
t.float "lng"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["order_id"], name: "index_addresses_on_order_id", using: :btree
end
OrdersController.rb
class OrdersController < ApplicationController
layout 'dashboard'
before_action :authenticate_user!
before_action :set_order, only: [:show, :edit, :update, :destroy]
before_action :load_resource
# insert generic boring stuff
private
# Use callbacks to share common setup or constraints between actions.
def set_order
@order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:invoice, :description, :weight, :length, :width, :height, :account_id, :driver_id, :status,
pickup_address_attributes: [:street1, :street2, :city, :state, :postal, :country],
dropoff_address_attributes: [:street1, :street2, :city, :state, :postal, :country],
pickup_contact_attributes: [:first_name, :last_name, :phone],
dropoff_contact_attributes: [:first_name, :last_name, :phone])
end
def load_resource
case params[:action].to_sym
when :show
if current_user.is_admin?
@drivers = Driver.within(5, :origin => @order)
end
end
end
end
使用&#39; lat&#39;更改我的纬度和经度列后,NEW ERROR和&#39; lng&#39;建议更改:
NEW error: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "user_locations"
LINE 1: ...M "users" WHERE "users"."type" IN ('Driver') AND (user_locat...
^
: SELECT "users".* FROM "users" WHERE "users"."type" IN ('Driver') AND (user_locations.lat IS NOT NULL AND user_locations.lng IS NOT NULL) AND (user_locations.lat>29.61103991439227 AND user_locations.lat<38.28523108560773 AND user_locations.lng>-88.97349091777367 AND user_locations.lng<-78.5259326822263) AND (((ACOS(least(1,COS(0.5925067393881714)*COS(-1.4617082185063466)*COS(RADIANS(user_locations.lat))*COS(RADIANS(user_locations.lng))+ COS(0.5925067393881714)*SIN(-1.4617082185063466)*COS(RADIANS(user_locations.lat))*SIN(RADIANS(user_locations.lng))+ SIN(0.5925067393881714)*SIN(RADIANS(user_locations.lat))))*3963.1899999999996) <= 300))
答案 0 :(得分:0)
让我们在这里清楚您尝试运行的方法是如何工作的
@drivers = Driver.within(5,:origin =&gt; @order)
您要发送给方法的origin属性需要是具有lat和lng属性的模型的实例,并且看起来顺序没有它们,例如,您有两个具有这些属性的模型属性addresses
和user_locations
只更改了具有你的lat和lng的实例的@order
答案 1 :(得分:0)
与this一样,gem中的through
已有很长时间了
解决方案是在model
和geokit
方法调用之间使用显式联接
driver
是user
的子类,并且user
具有geokit的方法并且可以通过user_location
进行映射
要使Driver.within(5, :origin => @order)
正常工作,您需要这样写
Driver.joins(:user_location).within(5, :origin => @order)