【问题标题】:How to pass user's browser geolocation (from javascript) to rails?How to pass user's browser geolocation (from javascript) to rails?
【发布时间】:2023-01-29 20:05:54
【问题描述】:

我目前正在使用request.location.coordinates 设置用户的坐标(纬度和经度),但位置不够准确。我想改用用户的浏览器地理位置。

如何将通过 javascript 获取的经纬度传递给 rails user_coordinates 变量?我读过你应该为此使用 AJAX,但我是初学者,不知道 AJAX 是如何工作的。特别是,我在各个地方都看到过代码 sn-ps,但我什至不知道将它们放入哪个文件中进行尝试。

更新:这里说我应该在 Rails 7 中为 Ajax 使用涡轮流——谁能帮我理解它是如何工作的? https://www.reddit.com/r/rails/comments/vfmymj/how_can_i_implement_ajax_in_rails_7/

控制器/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :set_user_coordinates

  def set_user_coordinates
    if Rails.env.production?
      @user_coordinates = request.location.coordinates
    end
  end
end

javascript/控制器/geolocation_controller.js

import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
  static targets = ['park'];

  connect() {
    window.navigator.geolocation.getCurrentPosition((position) => {
      this.setUserCoordinates(position.coords);
      this.setDistanceText();
    })
  }

  setUserCoordinates(coordinates) {
    this.element.dataset.latitude = coordinates.latitude;
    this.element.dataset.longitude = coordinates.longitude;
  }

  getUserCoordinates() {
    return {
      latitude: this.element.dataset.latitude,
      longitude: this.element.dataset.longitude,
    };
  }

  setDistanceText() {
    this.parkTargets.forEach((parkTarget) => {
      let distanceFrom = getDistance(
        this.getUserCoordinates(),
        { latitude: parkTarget.dataset.latitude,
          longitude: parkTarget.dataset.longitude },
      );

      parkTarget.querySelector('[data-distance-away]').innerHTML =
            `${Math.round(convertDistance(distanceFrom, 'km'))}`;
    });
  }

}

使用上下文:我正在使用位置数据根据与用户的距离对公园进行排序。我正在使用 Ransack 按距离排序,距离是通过 Geocoder near 方法设置的,该方法使用 user_coordinates 变量来计算距离:

控制器/parks_controller.rb

class ParksController < ApplicationController

  def index
    @parks = @q.result(distinct: true).includes(:visited_users, :favorited_users).near(@user_coordinates, 100000000).paginate(page:params[:page], :per_page => 24)
  end

end

【问题讨论】:

    标签: javascript ruby-on-rails ajax geolocation ransack


    【解决方案1】:

    要将经纬度从 JavaScript 传递到 Rails,您可以使用坐标作为数据向 Rails 端点发出 AJAX 请求。以下是如何修改 setUserCoordinates 方法来发出 AJAX 请求:

    setUserCoordinates(coordinates) {
      this.element.dataset.latitude = coordinates.latitude;
      this.element.dataset.longitude = coordinates.longitude;
    
      fetch('/set_coordinates', {
        method: 'post',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          latitude: coordinates.latitude,
          longitude: coordinates.longitude
        })
      });
    }
    

    在 Rails routes.rb 文件中,为 AJAX 请求添加一个新端点:

    Rails.application.routes.draw do
      post '/set_coordinates', to: 'geolocation#set_coordinates'
    end
    

    然后在 Rails 中创建一个新的控制器来处理 AJAX 请求:

    class GeolocationController < ApplicationController
      def set_coordinates
        session[:latitude] = params[:latitude]
        session[:longitude] = params[:longitude]
        head :ok
      end
    end
    

    最后,在您的 ApplicationController 中,修改 set_user_coordinates 方法以使用会话中的纬度和经度:

    def set_user_coordinates
      if Rails.env.production?
        @user_coordinates = [session[:latitude], session[:longitude]]
      end
    end
    

    通过这些更改,用户的纬度和经度将通过 AJAX 发送到服务器并存储在会话中,然后可以在 Rails 控制器中使用。

    关于 Turbo Streams,它是 Rails 7 中的一个新特性,它允许服务器和客户端之间进行实时通信。但是,对于上述解决方案,您不需要它。

    【讨论】: