Here's the situation. I work on a large Rails 3.2.13 app (Ruby 1.9.3, Bundler 1.3.5). We've recently begun the process of making this app less monolithic by breaking some components out into gems/engines. However, we have kept the source code in the same git repository. So we've got a file structure like:
APPNAME
|-app
|-gems
|---engine1
|---engine2
|-lib
etc.
Then the Gemfile looks like:
gem 'engine1', :path => File.expand_path('../gems/engine1', __FILE__)
gem 'engine2', :path => File.expand_path('../gems/engine1', __FILE__)
So far so good. My problem is that Gemfile.lock is no longer consistent between developers. Whenever I fetch changes from source control and run rspec or rails server or whatever, I get a modified Gemfile.lock where the diff looks like:
PATH
- remote: /Users/OTHER_DEVELOPER/PATH_TO_APP_SOURCE/gems/engine1
+ remote: /Users/ME/APPNAME/gems/engine1
We've always followed what we considered to be the best practice of checking our Gemfile.lock into source control, but now that's causing git headaches. Has anyone dealt with this problem before? Any ideas for a solution?
The problem here is that you're using gems in an unintended way. They are gems, not DLLs.
If you want a gem approach, host them on a private server and refer to that server in your GEMFILE.
If you want a DLL-like approach in ruby, just use a folder for each library.
Related
Ruby is so darn mysterious when it comes to using the gems! Where do these gems reside?? In java, you can have as many jars you want just include them in your CLASSPATH and your good to go. Ruby is a simpler language, but why do I need the headache of dealing with simple crap? Can anyone seriously finally explain how the gem loading process works? It seems like no one really knows why the heck do requiring some gems work, and requiring others doesn't even if you have gem installed them and they are in the gem list. Where is the authority in ruby on this site that can finally clarify the gem loading process.
I am tried of including 'rubygems' in my ruby scripts to prevent errors like LoadError: no such file to load -- pony
And even when I do require 'rubygems' in my scripts, it still gives LoadErrors. Even if the gem is in my gem list.
When you're using Bundler to manage Gems in your project (you will have a Gemfile at the root directory of the project), be sure to run
bundle install
requiring rubygems just loads rubygems itself (and isn't required in ruby 1.9 and above)
You need to actually load each gem individually via require.
If you use bundler, then you can optionally have bundle auto require everything from your Gemfile
I've forked a gem, and in trying to change it, decided to change the the gemfile from my git repository (which had been updating fine):
gem 'bootstrap-wysihtml5-rails', :git => 'git://github.com/Asherlc/bootstrap-wysihtml5-rails.git'
to the local directory (just the cloned git repository):
gem 'bootstrap-wysihtml5-rails', :path => '/Users/ashercohen/Documents/bootstrap-wysihtml5-rails'
Upon running either bundle update or bundle install, it shows the correct version number (updated since switching gem sources) in the readout. However, none of the files in the /vendor/assetspath seem to be getting updated in my Rails app. Is there some kind of caching thing I need to clear out?
I don't have a /vendor/cache file in my Rails app, and I'm confident that since the gem version is updating correctly in the bundler readout that the path is correct.
Is there some step I'm missing here?
Turns out Chrome was just aggressively caching the JS.
To help understand the source code of various gems I often want to place various puts statements in the source code or even try using the ruby debugger.
But whats the best way of doing this?
Do you clone the project from github and make changes locally, if so how do you "force" the use of the local cloned code over the local gem on your machine. Do I just create some scripts that explicitly require the path of the cloned repos folder?
Or do should I use rvm to create a temp gemset, download the gem and modify it directly?
Are there any other methods ive overlooked? How would this change for gems designed for use within rails projects.
The way I usually do it when I want to make changes to a Gem:
Fork the repository on Github
Check it out and create a new branch for local changes
Use Bundler to manage dependencies for the project which uses the Gem
Change one line in the Gemfile to make it use the forked version of the Gem:
gem "thegem", :git => "git://github.com/name/thegem.git", :branch => 'mybranch'
or
gem "thegem", :git => "file:///path/to/thegem", :branch => 'mybranch'
with /path/to/thegem being the path to your local working copy.
The advantage is that you now already have a the perfect infrastructure set up for contributing your changes through a pull request :)
With Bundler.
In a Rails app simply edit the Gemfile and add:
gem "gem_name", :path => "~/MyGems/gem_name"
PS: Bundler work with any Ruby project.
You can use rvm to create a temp gemset, download the gem and modify it directly. A fast way to view/modify a gem is using gemedit :
Install:
gem install gemedit
Usage:
gem edit devise
or: gem edit devise -e mate
I'm writing an app that will run scripts in a specified folder, and then record the numbers and graph them.
My problem is that if the script is a ruby file, the require statements fail inside the script because bundler seems to have done something funky with the load path.
Running rails runner Datasource.run_jobs fails:
class Datasource < ActiveRecord::Base
def self.run_jobs
require 'aws_sdb'
access_key_id = "REDACTED"
secret_key = "REDACTED" # In all actuality these woudln't be here.
#sdb = AwsSdb::Service.new(:access_key_id => access_key_id, :secret_access_key => secret_key)
Datasource.all.each do |ds|
puts "Updating #{ds.name}..."
unless #sdb.list_domains.include? ds.name
puts "#{ds.name} doesn't exist in SDB, creating a domain for it..."
#sdb.create_domain ds.name
end
#data = "TEST"
data = `#{RAILS_ROOT}/lib/plugins/#{ds.name}`
#sdb.put_attributes(ds.name, Time.now.to_i, data)
puts "Data Collected: #{data.inspect}"
end
end
has_many :graphs
end
(Basing this off your comments on the question)
You will need to add hpricot (and any other gem this needs) to your Gemfile so that they are made available by Bundler. Bundler is by far the easiest way to avoid gem conflicts and tomfoolery.
Imagine this situation: You somehow lose the gems that you have currently. Be this happening through a format or system change or any other reason. Whatever it is, you've lost your gems. How are you going to re-install all your gems? You could keep a list of them somewhere else yourself, but is this truly likely?
Bundler solves this problem by making you state what gems your application requires and only adding those gems to the load path, which is why you can't find hpricot. When you run bundle install the first time, this creates a Gemfile.lock which contains something like this:
GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
actionmailer (3.0.0)
...
Because you commit this file to your source control "solution" of choice (be it Git, SVN, FTP, whatever, it's not important) you have a solid way of specifying the precise gems and precise versions of those gems that your application uses.
When/If your gems are wiped, you can simply clone your project again and run bundle install. Because the Gemfile.lock file exists, you'll have exactly the same gems you had originally, even if there were updates.
If you don't want the exact same gems, just run bundle update and this will ignore the specifications in Gemfile.lock and instead revert to depending on Gemfile to define them. This will check for new versions of gems and install them, updating the Gemfile.lock when it's done.
Honestly, I don't understand the Bundler hate. If you could explain in wider terms than "OMG IT SUCKS YEHUDA IS SATAN", I'd be much obliged.
Edit: WedTM asked for a sample Gemfile and related code:
In the Gemfile you'd have this:
group(:scripts) do
gem 'gem1'
end
To require these gems for your scripts:
require 'bundler'
Bundler.require(:scripts)
You may also wish to require the default gems too which you can do by just adding default anywhere to the arguments of require:
Bundler.require(:default, :scripts)
If this for some reason doesn't work I would imagine it would be because it can't locate the Gemfile. This can be fixed by setting the ENV['BUNDLE_GEMFILE'] to the path to the Gemfile.
I wonder if you might be able to use RVM to set up the ruby environment before running your scripts. Maybe something with a gemset like:
data = `rvm gemset use scripts; #{RAILS_ROOT}/lib/plugins/#{ds.name}`
When I try to deploy my rails app to my shared hosting (dreamhost) I get this error:
can't activate rack (~> 1.0.1, runtime) for [], already activated rack-1.0.0 for []
So I want to freeze the rack gem in my dev environment, and add it to the project, but even though I have this in my config/environment.rb:
config.gem 'rack'
Doing a rake gems:unpack:dependencies doesn't freeze the gem.
ajmbp:trunk ajl$ rake gems:unpack:dependencies
(in /Users/ajl/dev/site/trunk)
ajmbp:trunk ajl$ ll vendor/gems/
.svn/ haml-2.2.14/ net-ssh-2.0.16/
I tried adding another gem to the config.gem just to test (RedCloth) and that does work as expected, but no luck with rack.
Any ideas?
Thanks!
Have you checked your environment variables (RUBY_GEMS I think it is, or something like that)?
Also, your environment.rb and (if you use fastcgi) your .fcgi.
Make sure the paths are ordered from highest priority to lowest.
See this article.
Any gem that is loaded in your Rakefile (e.g. metric_fu, vlad, etc) is considered to be a ‘framework gem’ by Rails, and such gems are not unpacked. Given that the vendor/gems directory is not yet in the load path when the Rakefile is loading, this is probably a good idea.
In other words, if you have a library that provides Rake tasks, or is otherwise necessary for your .rake files to be valid, don’t expect “config.gem” and friends to handle it for you.
For Dreamhost see their own documentation on installing your own gems. Or see this excellent article on how to load your own packages and gems (be warned it's not for the faint of heart).
But all my reading is telling me that you may still run into trouble because of the way Passenger may be using the Rack version installed by Dreamhost.
Good Luck.