Rails升级后CustomGoogleDirections调用出现Errno::ENOENT错误排查
我定义了继承自GoogleDirections的CustomGoogleDirections类,设置了Google Directions API的XML接口地址。在控制器中调用该类,传入地点参数计算路线英里距离与分钟级驾驶时间,Rails版本升级后出现Errno::ENOENT错误(提示文件或目录不存在)。直接访问生成的API链接可正常获取经纬度等信息,请问问题出在哪里?
相关代码如下:
class CustomGoogleDirections < GoogleDirections @@base_url = "https://maps.googleapis.com/maps/api/directions/xml" end
控制器调用代码:
@locations = @all_locations.each_cons(2).with_index.with_object({}) do |((e1, e2), i), h| h[i + 1] = [e1, e2, CustomGoogleDirections.new(e1, e2, key: Figaro.env.google_translate_secret_key).distance_in_miles, CustomGoogleDirections.new(e1, e2, key: Figaro.env.google_translate_secret_key).drive_time_in_minutes.url] end
错误信息:
Errno::ENOENT (No such file or directory @ rb_sysopen - https://maps.googleapis.com/maps/api/directions/xml?destination=60%2BBarron%2BRoad%252C%2BDubai%252C%2BDubai&key=######################&origin=60%2BAlFhaged%2BRoad%252C%2BDubai%252C%2Dubai)
原因
这个错误的核心是:Ruby/Rails版本升级后,open-uri的默认行为发生了变化,或者GoogleDirections gem内部使用了File.open这类本地文件操作方法来请求远程HTTPS URL,而新版本的Ruby不再允许这种直接把远程URL当作本地文件处理的操作,导致系统误以为要打开本地目录下的文件,从而抛出“文件或目录不存在”的错误。
修复方案
检查并升级
GoogleDirectionsgem
先确认该gem是否有适配新版本Ruby/Rails的更新,直接升级gem版本是最简单的解决方案。如果gem已经停止维护,则需要手动修改请求逻辑。重写自定义类的请求逻辑
在CustomGoogleDirections类中替换底层的请求方式,使用标准的HTTP客户端(比如Net::HTTP)来获取API响应,替代原来依赖open-uri的逻辑:class CustomGoogleDirections < GoogleDirections @@base_url = "https://maps.googleapis.com/maps/api/directions/xml" # 重写gem中获取响应的方法,改用Net::HTTP请求 def fetch_response uri = URI.parse(build_url) response = Net::HTTP.get_response(uri) raise "API请求失败: #{response.message}" unless response.is_a?(Net::HTTPSuccess) response.body end # 替换gem中原有的解析响应方法,使用新的fetch_response def parse_response @response ||= Nokogiri::XML(fetch_response) end end注:具体需要重写的方法名可能需要参考
GoogleDirectionsgem的源码,确保覆盖原来使用open-uri的逻辑。优化控制器代码(额外建议)
控制器中重复实例化CustomGoogleDirections会导致重复请求API,既浪费资源又降低性能,建议修改为只实例化一次:@locations = @all_locations.each_cons(2).with_index.with_object({}) do |((e1, e2), i), h| directions = CustomGoogleDirections.new(e1, e2, key: Figaro.env.google_translate_secret_key) h[i + 1] = [e1, e2, directions.distance_in_miles, directions.drive_time_in_minutes.url] end
内容的提问来源于stack exchange,提问作者Rene Chan

