You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails项目中Google Places API创建Restaurant对象报错求助

问题排查与修复方案

1. 解决INVALID_REQUEST错误(字段参数问题)

Google Places API的fields参数有严格的字段名规范,不存在的字段会直接返回无效请求:

  • 确认你调用的是Place Details API(用于获取餐厅详情),该API允许的字段包括name、formatted_address、website、geometry、photos等,注意字段名全小写,无拼写错误
  • 若误用了Geocoding API,它不支持fields参数,需切换到正确的Place Details端点:https://maps.googleapis.com/maps/api/place/details/json,且必须携带有效的place_id参数(不能直接传地址)

2. 解决无候选结果问题

Place Details API无法直接解析地址,必须先将地址转换为place_id:

  • 使用Geocoding API将精确地址转成place_id,示例代码:
    geocode_url = "https://maps.googleapis.com/maps/api/geocode/json?address=#{URI.encode(params[:restaurant][:address])}&key=#{ENV['GOOGLE_PLACES_API_KEY']}"
    response = HTTParty.get(geocode_url)
    place_id = response['results'].first['place_id'] if response['status'] == 'OK'
    
  • 确保地址格式完整(包含国家、城市等信息),若Geocoding API也返回无结果,检查地址是否准确,或API密钥是否启用了Geocoding API权限

3. 潜在问题排查与优化

3.1 API密钥与权限

  • 确认Google Cloud项目已启用Places API和Geocoding API
  • 检查API密钥的限制规则(如IP限制、API范围限制),避免因权限不足导致请求失败

3.2 Active Storage图片处理

从Places API获取图片需处理photo_reference字段:

  • 拼接图片URL:
    photo_ref = place_data['photos'].first['photo_reference']
    photo_url = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=800&photoreference=#{photo_ref}&key=#{ENV['GOOGLE_PLACES_API_KEY']}"
    
  • 下载并附加到Active Storage,同时处理无图片的情况:
    require 'open-uri'
    if place_data['photos'].present?
      begin
        @restaurant.image.attach(io: URI.open(photo_url), filename: "#{@restaurant.name}_photo.jpg", content_type: 'image/jpeg')
      rescue => e
        Rails.logger.error "图片下载失败:#{e.message}"
      end
    end
    

3.3 错误处理

必须覆盖API返回的所有状态码,避免空指针或逻辑崩溃:

case response['status']
when 'OK'
  # 正常处理数据
when 'ZERO_RESULTS'
  flash[:alert] = "无法识别该地址"
when 'OVER_QUERY_LIMIT'
  flash[:alert] = "API配额不足,请稍后再试"
when 'REQUEST_DENIED'
  flash[:alert] = "API密钥无效或权限不足"
else
  flash[:alert] = "请求失败:#{response['status']}"
end

3.4 环境变量管理

不要硬编码API密钥,用dotenv-rails gem管理环境变量,通过ENV['GOOGLE_PLACES_API_KEY']调用,避免密钥泄露

完整流程示例代码

class RestaurantsController < ApplicationController
  def create
    address = params[:restaurant][:address]
    # 1. 地址转place_id
    geocode_response = HTTParty.get("https://maps.googleapis.com/maps/api/geocode/json?address=#{URI.encode(address)}&key=#{ENV['GOOGLE_PLACES_API_KEY']}")
    
    if geocode_response['status'] != 'OK' || geocode_response['results'].empty?
      flash[:alert] = "无法识别该地址,请检查输入"
      redirect_to new_restaurant_path and return
    end

    place_id = geocode_response['results'].first['place_id']
    # 2. 获取餐厅详情
    place_response = HTTParty.get("https://maps.googleapis.com/maps/api/place/details/json?place_id=#{place_id}&fields=name,formatted_address,website,photos&key=#{ENV['GOOGLE_PLACES_API_KEY']}")

    if place_response['status'] != 'OK'
      flash[:alert] = "获取餐厅信息失败:#{place_response['status']}"
      redirect_to new_restaurant_path and return
    end

    place_data = place_response['result']
    # 3. 创建Restaurant实例
    @restaurant = Restaurant.new(
      name: place_data['name'],
      address: place_data['formatted_address'],
      website: place_data['website']
    )

    # 4. 处理图片
    if place_data['photos'].present?
      photo_ref = place_data['photos'].first['photo_reference']
      photo_url = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=800&photoreference=#{photo_ref}&key=#{ENV['GOOGLE_PLACES_API_KEY']}"
      begin
        @restaurant.image.attach(io: URI.open(photo_url), filename: "#{@restaurant.name}_main.jpg", content_type: 'image/jpeg')
      rescue => e
        Rails.logger.error "图片下载失败:#{e.message}"
      end
    end

    if @restaurant.save
      redirect_to @restaurant, notice: "餐厅创建成功"
    else
      render :new
    end
  end
end

内容的提问来源于stack exchange,提问作者BrownKid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:27:39