views:

73

answers:

4

I'm trying to set up an RVM gemset through a Rails 3 template and then, via commands in the template, start using the gemset and install the gems into the new gemset (named after the app). This does not seem to work properly. The new gems do not get installed into the gemset and in fact the gemset does not get created at all.

Here's some of the relevant code extracted from the template file:

rvmrc = <<-RVMRC
rvm_gemset_create_on_use_flag=1
rvm_trust_rvmrcs=1
rvm gemset use #{app_name}
RVMRC

create_file ".rvmrc", rvmrc

Then, further down the road:

run "cd path/to/new/app"
run 'gem install bundler --pre'
run 'bundle install'

I also tried a different version:

inside app_name do 
  run 'gem install bundler --pre'
  run 'bundle install'
end

And a third version:

inside app_name do 
  run "rvm gemset create #{app_name} && rvm gemset use #{app_name}"
  run 'gem install bundler --pre'
  run 'bundle install'
end

It works perfectly if I just cd into the new app folder in the console after the template has run. I get the RVM message: "info: Now using gemset 'test_app'." If I run the bundle install command at that point, the gems get correctly installed into the new gemset, but I can't get the same result if I just run those commands from the template file.

The log for the app generator says this:

 run    cd ~/rails3_sites/test_app from "."
 run    gem install bundler --pre from "./test_app"
 run    bundle install from "./test_app"

What am I missing? Any help is greatly appreciated. I am using ruby 1.9.2, by the way.

Thanks,

~ Andrea

A: 

Any luck with this? I've come across the same problem.

Daniel Insley
A: 

I have recently revisited this problem. It can be accomplished using the RVM Ruby API. I placed the calls to the API in a Ruby file separate from my template as follows:

rvm_lib_path = "#{`echo $rvm_path`.strip}/lib"
$LOAD_PATH.unshift(rvm_lib_path) unless $LOAD_PATH.include?(rvm_lib_path)
require 'rvm'

rvm_ruby = ARGV[0]
app_name = ARGV[1]

unless rvm_ruby
  puts "\n You need to specify a which rvm rubie to use."
end

unless app_name
  puts "\n You need to name your app."
end

@env = RVM::Environment.new(rvm_ruby)

puts "Creating gemset #{app_name} in #{rvm_ruby}"
@env.gemset_create(app_name)
puts "Now using gemset #{app_name}"
@env.gemset_use!(app_name)

puts "Installing bundler gem."
puts "Successfully installed bundler" if @env.system("gem", "install", "bundler")
puts "Installing rails gem."
puts "Successfully installed rails" if @env.system("gem", "install", "rails")

template_file = File.join(File.expand_path(File.dirname(__FILE__)), 'templater.rb')
system("rails new #{app_name} -JT -d mysql -m #{template_file}")

If anyone is interested I have written up a blog post about Rails 3 templates in general that goes into this in more detail:

Cooking Up A Custom Rails 3 Template

Andrea S.
A: 

Andrea, excellent approach and a fabulous blog article. However, the RVM bootstrap doesn't work.

Here are roughly the same steps in irb to create a new gemset:

ree-1.8.7-2010.02 > require 'rvm'
true
ree-1.8.7-2010.02 > @env = RVM::Environment.new('ree')
#<RVM::Environment environment_name="ree">
ree-1.8.7-2010.02 > @env.gemset_create('some_gemset')
true
ree-1.8.7-2010.02 > @env.gemset_use!('some_gemset')
true
ree-1.8.7-2010.02 > @env.gemset_name
nil
ree-1.8.7-2010.02 > 

Notice the last line attempts to read the current gemset, which is nil (the terminal session was using the default gemset, thus it's empty). I expected it to show 'some_gemset'. I essentially get the same behavior when running your script: it installs the gems into whatever gemset I happen to be in when running the script.

Any thoughts or suggestions on this strange behavior?

Jeff Poulton
Hi Jeff, I couldn't recreate the behavior you described. However, I'm using Ruby 1.9.2 (@env = RVM::Environment.new('ruby-1.9.2-p0')). It could have something to do with the particular version of Ruby you are using or even with the version of RVM. Try running 'rvm update' to upgrade RVM to the latest version. Let me know if this persists. I'd like to make sure that the script is not tied to a particular version of Ruby.
Andrea S.
A: 
rvm_lib_path = "#{`echo $rvm_path`.strip}/lib"
$LOAD_PATH.unshift(rvm_lib_path) unless $LOAD_PATH.include?(rvm_lib_path)
require 'rvm'

rvm_ruby = ARGV[0]
app_name = ARGV[1]

unless rvm_ruby
  puts "\n You need to specify a which rvm rubie to use."
end

unless app_name
  puts "\n You need to name your app."
end

@env = RVM::Environment.new(rvm_ruby)
ENV['RVM_RUBY'] = rvm_ruby

puts "Creating gemset #{app_name} in #{rvm_ruby}"
@env.gemset_create(app_name)
puts "Now using gemset #{app_name}"
@env = RVM::Environment.new("#{rvm_ruby}@#{app_name}")


puts "Installing bundler gem."
puts "Successfully installed bundler" if @env.system("gem install bundler --no-ri --no-rdoc")
puts "Installing rails gem."
puts "Successfully installed rails" if @env.system("gem install rails --no-ri --no-rdoc")

template_file = File.join(File.expand_path(File.dirname(__FILE__)), 'template.rb')
system("rvm #{rvm_ruby}@#{app_name} exec rails new #{app_name} -JT -d mysql -m #{template_file}")

system("mv #{app_name} #{app_name}.git")

works.

There's a bug with rvm where the @rvm_environment instance variable does not get set properly using gemset_use! so if you do @env.send(:instance_variable_get, :@rvm_environment) it does not reflect the updated gemset so when you call system it does not execute in the right environment/gemset. Re-setting the @env var to a new RVM::Environment instance fixes the problem.