新手问题 想在一个 Rails 项目里使用同一个 gem 的不同版本,有什么好的实现方式

ane · 2017年05月09日 · 最后由 zlx_star 回复于 2017年05月11日 · 1866 次阅读

简单举例,一个 rails 项目里,使用了 redis 的 3.0.4 和 3.3.3 两个版本,想要在不同的 url 里动态使用不同 redis 版本

刚刚折腾了半天,终于找到一个方式,思路就是别在 gemfile 中添加任何 gem 的依赖,采用 $LOAD_PATH 加入依赖,每次 require 一个 gem 以后,记得使用完的时候在全局里删掉

$LOADED_FEATURES.delete

大概的代码是这样的

def set_book
  if  params[:id] == "1"
   $LOADED_FEATURES.delete_if{|a|  a.include?("redis-3.3.3")}
   $LOAD_PATH.unshift File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.0.4/lib',root)

  require File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.0.4/lib/redis', root)
  elsif  params[:id] == "2"
    $LOADED_FEATURES.delete_if{|a|  a.include?("redis-3.0.4")}
   $LOAD_PATH.unshift File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.3.3/lib', root)
  require File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.3.3/lib/redis', root)
  end
  @book = Book.find(params[:id])
end

不能。

拆成两个项目

Rei 回复

改写 bundle 或者,改写 require 的功能,理论上应该可以实现

4楼 已删除
ane 回复

还要改写 Ruby 的命名域。

Rei 回复

是啊,这就是最麻烦的地方

同一个 Rails App 里面不能这么用。不过,你先说说需求,为什么要不同 URL 调用不同的 gem 版本,或许有其他办法

kgen 回复

我没有在 gemfile 里添加 redis

def set_book
   if  params[:id] == "1"
    $LOADED_FEATURES.delete_if{|a|  a.include?("redis-3.3.3")}
    $LOAD_PATH.unshift File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.0.4/lib',root)
   require File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.0.4/lib/redis', root)
   elsif  params[:id] == "2"
     $LOADED_FEATURES.delete_if{|a|  a.include?("redis-3.0.4")}
    $LOAD_PATH.unshift File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.3.3/lib', root)
   require File.expand_path('vendor/bundle/ruby/2.3.0/gems/redis-3.3.3/lib/redis', root)
   end
   @book = Book.find(params[:id])
 end

这种方式,貌似还是可以

搞到另外一个项目 2 里包成 service 在 1 项目里调用

真是奇怪的需求啊

奇葩的需求。 觉得这种设计很不稳定,不如花点时间统一一下。。。

还是重构统一一下吧。。。。

很好奇为什么会需要两个不同的版本

kgen 回复

很想吐槽云梯,毕竟好几年的用户了,自从升级到 sierra,各种办法都试过了,就是连不上

ane 回复

天天在 Sierra 用云梯的表示,这个系统下连接无问题。有困难请找客服,临床经验丰富,一定能帮你解决的。

我很想知道为什么要这样做。

我最近也遇到过这种问题, 我的工作环境是插件, 可能遇到和别的插件撞 gem 的情况, 我的解决方案和你差不多, 在 require 前缓存可能有的 gem 对象, 清理 $LOADED_FEATURES.后加载自己的 gem 然后把 gem 对象转移到一个 module 中, 最后再把缓存的 gem 给放回去, 这样就能通过增加命名空间的方式同时存在好几个版本的 gem 了

qichunren 回复

因为我要测试不同 gem 的兼容性

在不同的目录下,分别创建项目,使用不同的 Gemfile。

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