7

I have a class unzipper.rb that unzips a file using Rubyzip.

In my local environment, I can succesfully unzip a file without explictly including the dependency using require 'zip'

On Heroku though, I get an NameError (uninitialized constant Unzipper::Zip) which I could only resolve by using the explict require

Question: Why would this be necessary in the Heroku environment, but not on localhost? I was under the impression that Rails required all gems automatically.

app/services/unzipper.rb

require 'zip'  # Only required for Heroku. Works locally without!

class Unzipper

  OVERRIDE_FILES = true

  def initialize(file)
    @file = file
  end

  def self.unzip(file, &block)
    Unzipper.new(file).unzip(&block)
  end

  def unzip
    open_zip do |zip|
      yield extract_files(zip)
    end
  end

  private

  def open_zip(&block)
    ::Zip::File.open(@file.path, &block)
  end

  def extract_files(zip)
    files = []
    zip.each do |entry|
      path = "#{rails_temp_directory}/#{entry.name}"
      entry.extract(path) { OVERRIDE_FILES }
      files << path
    end
    files
  end

  def rails_temp_directory
    "#{Rails.root}/tmp"
  end
end

Heroku output when running bundler includes:

remote:        Using rubyzip 1.1.7

I verified both are using the same version of Ruby.

There is no initializer or environment config for Rubyzip.

Gemfile

source 'https://rubygems.org'

gem 'rails', '4.2.0'

gem 'pg', group: :production

gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc

gem 'slim-rails'

gem 'paperclip'
gem 'rest-client'

gem 'bootstrap-sass', '~> 3.3.3'

gem 'validates_serialized'

gem 'puma'

gem "nokogiri"
gem "cocoon"
gem 'sidekiq'
gem 'sinatra', :require => nil # For sidekiq web monitoring
gem 'aws-sdk', '< 2.0'
gem 'rails_12factor', group: :production
gem 'rubyzip'

group :development, :test do
  gem 'byebug'

  gem 'web-console', '~> 2.0'

  gem 'spring'

  gem 'sqlite3'

  gem 'shoulda-matchers'
  gem 'rspec-rails'
  gem 'factory_girl_rails'
  gem 'capybara'
  gem 'selenium-webdriver'
  gem 'database_cleaner'
  gem 'guard-rspec'
  gem 'faker'
end

group :test do 
  gem 'webmock'
end

ruby '2.2.0'
madcow
  • 2,567
  • 14
  • 31
  • Probably an environment issue. Try setting your local `RAILS_ENV` to `production` to see if the same problem happens. – Leo Brito Sep 22 '15 at 15:26
  • Do you run your script via `bundle exec`? – Alexey Shein Sep 22 '15 at 15:54
  • @brito I'm away from my office but will try that! – madcow Sep 22 '15 at 15:56
  • @Alexey this is called from a rails controller and I assume heroku runs rails with bundle exec? – madcow Sep 22 '15 at 15:56
  • 3
    Can you share a stacktrace of the error? The big difference between production and dev environments is that files are being eagerly loaded in production by default. rubyzip's main file name is different than its gem name, so you might have to specify it explicitly in the Gemfile: `gem 'rubyzip', require: 'zip'` – fivedigit Sep 22 '15 at 17:32
  • @fivedigit that fixed it and I learned something new :) Thanks! If you post your answer I'll accept it. – madcow Sep 23 '15 at 13:13

1 Answers1

14

Rubyzip's main file name is different than its gem name, so you might have to specify it explicitly in the Gemfile:

gem 'rubyzip', require: 'zip'
fivedigit
  • 18,464
  • 6
  • 54
  • 58
  • Nice! This worked for me. I feel like I would have never figured that out. High five @fivedigit! – jacklin Sep 01 '16 at 22:02