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

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

简单举例,一个 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。

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