Gem Grape 如何实现不需要重启服务器,自动编译 reload

lytsingsun · 2013年11月18日 · 最后由 huacnlee 回复于 2016年07月11日 · 6710 次阅读

Create config/initializers/reload_api.rb.

if Rails.env.development?

  ActiveSupport::Dependencies.explicitly_unloadable_constants << "Twitter::API"

  api_files = Dir["#{Rails.root}/app/api/**/*.rb"]
  api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do
    Rails.application.reload_routes!
  end
  ActionDispatch::Callbacks.to_prepare do
    api_reloader.execute_if_updated
  end

end

这个报错啊!

尝试了 rubychina 的源码,修改之后刷新浏览器也不是每次都起作用……

Rails 4 跑,用新版本的 Grape 自动 reload 已经不是问题了

#1 楼 @huacnlee Rails3.2.13 不行是吧?有解决的办法吗?

#1 楼 @huacnlee 没找到对应的文档。可以发个链接吗?

#4 楼 @ruby_sky Grape 0.6.0 版本 + Rails 4 就可以了,只需要在 application.rb 里面设置就可以了

config.paths.add "app/api", :glob => "**/*.rb"
config.autoload_paths += %W(#{config.root}/app/**/*)

Ruby China 的不行,Ruby China 的 Grape 不是新版本

#2 楼 @lytsingsun 3.2 也是可以的啊,放在 app/api 下本来就是可以的,在 application.rb 中加上

config.autoload_paths += %W(#{config.root}/app/api)

我们的做法是这样的:

config.ru 文件中设置

if Rails.env.production?
  map '/api' do
    run App.instance
  end
end

routes.rb 文件中设置

mount App.instance => '/api' unless Rails.env.production?

App.instance 是一个包装的 rack app,可以加一些 middleware

这样在生产环境下就可以直接到 api,不用走 rails 这一层,在开发环境下走 rails,这样代码也可以自动加载,更新。

#5 楼 @huacnlee 一定需要 rails 4? 3 不行?

#7 楼 @kamechen 3 我不知道,我只是说 4 + Grape 0.6.0+ 的话,是可以的

#6 楼 @kamechen 按照你的建议我修改了下,uninitialized constant App (NameError)。不知是不是我有什么地方配置的不对. config.ru 文件

# This file is used by Rack-based servers to start the application.

require ::File.expand_path('../config/environment',  __FILE__)
run Rongyi::Application

if Rails.env.production?
  map '/grape' do
    run App.instance
  end
end

routes.rb 文件

require 'api'
mount App.instance => '/grape' unless Rails.env.production?

application.rb 文件

config.autoload_paths += %W(#{config.root}/app/grape)

#8 楼 @huacnlee 4 + Grape 0.6.0+ 是可以的。第一次用 rails4+grape 的时候真没留意到不需要加 reload_api.rb。

#6 楼 @kamechen 我是有什么地方弄错了吗?求解答……

#11 楼 @lytsingsun App 是我们自己定义的一个类,在 app/api 目录下, 类似下面这样

class App
  def self.instance
    @instance ||= Rack::Builder.new do      
      use Middlewares::Logger, Api.logger
      run Api
    end.to_app
  end
end

这个只是用来加入一些 middleware 的,如果你不需要,你也可以直接吧 App.instance 换成你的 Api

我们 3.2.12 实现了 auto reload, 以上说的都是必须步骤 但是楼主可能还有一个地方没有改掉

# config/initializers/reload_api.rb

if Rails.env.development?
  ActiveSupport::Dependencies.explicitly_unloadable_constants += [
# 这里列出需要自动reload的类
    'V1::OutlineApi','V1::UserApi','V1::FavoriteApi','V1::ArticleApi','V1::CommentApi',
    'V1::FriendshipApi', 'V2::FriendshipApi'
  ]

  api_files = Dir["#{Rails.root}/app/api/**/*.rb"]
  api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do
    Rails.application.reload_routes!
  end

  ActionDispatch::Callbacks.to_prepare do
    api_reloader.execute_if_updated
  end
end

比较笨的办法但是好歹实现了。

#2 楼 @lytsingsun Rails4+ 是可以的,我亲测过。Rails3 不清楚。如果是纯 Rack Server,可以尝试在 config.ru 下面增加如下代码:

if ENV['RACK_ENV'] == "development"
  use Rack::Reloader
end

#14 楼 @shawnyu 不行啊,还有什么地方需要注意吗?

啊。更正一下。如果是纯 Rack Server,最好的办法是用 shotgun 当做开发环境的 server。

#13 楼 @lytsingsun 不好意思,是我弄错了,我们那个也是在 Rails 4 的版本下做的, Rails 3 下还不支持自动 reload,在 Rails 3 下要解决这个问题,14 楼 @shawnyu 的方法应该可以,17 楼 @Victor 说的 shotgun 也是可以的,只是 shotgun 可能会比较慢

#18 楼 @kamechen 谢了哦,看来得放弃了

@lytsingsun 5 楼提到的东西都设置了吗?

#20 楼 @shawnyu 5 楼给的是 Rails4 的办法。楼主问的是 Rails3。

Rails 3 同样需要。

我只改了这些。 然后吧 Twitter::Api 那个换掉就行了

#24 楼 @shawnyu 哦哦,试了,确实不行啊

Grape on Rails

Rails 3.2.14 Grape 0.6.1

刚刚遇到这个问题,实测 autoload 可以搞定

routes.rb

require_dependency 'api_v2/grape' if Rails.env.development?
mount ApiV2::Grape => '/'

application.rb

config.watchable_dirs['api_v2'] = [:rb]
config.autoload_paths << "#{config.root}/api_v2"

如果是任意项目呢?非 Rails 比如 Sinatra 可以自动加载么?

#5 楼 @huacnlee 我的 application.rb 里添加:

config.paths.add "app/api", :glob => "**/*.rb"
config.autoload_paths += %W(#{config.root}/app/**/*)

环境:

  • Rails 4.0.2
  • Grape 0.7.0 修改 api.rb,not work,还需要重启 server

@huacnlee 貌似现在 RubyChina code 还是 API 不会自动 reload,修改起来挺麻烦的

找到一个 workaround,用 shotgun config.ru 启动,就自动 reload 文件,这样就不担心自动启动了

#27 楼 @zangcw 实现 rack 应用加载的几种方法:

Reload feature in development environment

run: bundle exec guard #eg. grape-on-rack

这个问题,我最近找到真正原因了,需要确保 API 代码存放的目录复合 Rails Autoload 的命名规范。

很多项目 (Ruby China、GitLab)早起的 API 代码在 module 命名,和文件存放的位置上是不规范的,理论上在 autoload_paths 里面加上了 lib/api 以后,就无须手动 require 的,命名符合 Rails 标准,加载会自动执行,同时 reload 的时候能正确清理。

正确的命名(Class、Module 和文件夹命名)以后,你就不会再遇到这样的错误:

Error: A copy of Gitlab::CurrentSettings has been removed from the module tree but is still active

参考:

需要 登录 后方可回复, 如果你还没有账号请 注册新账号