ImageScience breaks on update to Rails 3 - ruby-on-rails

I had a working (and working well) ImageScience install, that did some simple resizing to various dimensions of images, and then copying them to different directories. All very simple. This small and simple routine was in a rake task. Upon update to Rails 3, this rake task will still work (it does some AR inserts and audio encoding as well), but the image_science require fails with a message like this,
"require on /home//.ruby_inline/Inline_ImageScience_cdab.so failed"
I've ruled out a duff ImageScience install, as I can go into IRB and do some simple calls to ImageScience and make thumbnails. The remainder of the rake task works as well as it did before if I comment out any mention of requiring 'image_science' or the ImageScience routine.
the output from rake on failure is this,
/var/lib/gems/1.8/gems/RubyInline-3.8.6/lib/inline.rb:513:in `load'
/var/lib/gems/1.8/gems/RubyInline-3.8.6/lib/inline.rb:829:in `inline'
/var/lib/gems/1.8/gems/image_science-1.2.1/lib/image_science.rb:90
...
<active_support complaints >
...
/home/<user>/RailsApps/marlow/lib/tasks/flac_import.rake:2
...
<rails complaints>
...
/home/<user>/RailsApps/marlow/Rakefile:7
...
<standard complaints to end>
the Rakefile in the rails app root is a stock and standard Rails 3 Rakefile, like this,
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
Marlow::Application.load_tasks
the last line is line 7.
I'm kind of stumped as to what's breaking it, and Google doesn't seem to shed anything. Does anyone know why RubyInline is complaining? Or why this once working Rake task is suddenly unhappy how ImageScience is being called? OS is Ubuntu 10.10, but it was all working prior to the Rails 3 upgrade.
Thanks in advance

This does seem to be the problem, but there is a simpler fix I found from perusing the comments at carlhuda issues 431
I had the same problem and it worked for me. Simply change the require method to be Kernel.require.
After that there's no need to pepper your code with require image_science statements.

There is a fix, but you'll need to jump through few hoops.
First delay image_science load:
gem 'image_science', :require => false
Then monkey patch ruby-inline (which image_science relies on). Place this code in config/initializers/ruby_inline_hack.rb:
class Inline::C
def load
require "#{so_name}"
#below is the original version which breaks
#require "#{so_name}" or raise LoadError, "require on #{so_name} failed"
end
end
Then require 'image_science' wherever you're using it. And voila.

One note on aremave's answer:
It looks like the original code has a bug! It's not using short-cut-evaluation!
class Inline::C
def load
require "#{so_name}" || raise LoadError, "require on #{so_name} failed"
end
end
Notice the || , which will stop the evaluation of the logical expression if the first part is true.
If there is an 'or' in the same place, the second part of the expression will always be evaluated,
hence the error you're seeing...

as seen on bundler issue tracker, it worked for me.
Point your gem file to https://github.com/asynchrony/image_science We rebuilt image science without ruby inline.

Related

Rails REPL that is more than irb/pry but less than rails console

I frequently want to try out small code snippets, often much smaller than classes, and even functions, just to make sure it works by itself so I don't need to test it by running a bunch of scripts, simply to fix small errors in a line of code or so.
Besides irb/pry, I want to test Rails-specific code, such as Object.blank?. So with that, I want to have the Rails library loaded, but I don't need the full functionality that Rails console gives me. Especially when the application is not in a working state, the REPL will not open at all, and merely present a stack trace of the failure at hand.
If anybody knew how to achieve this middle ground, maybe through the use of a particular gem path and require statement to load one of the other REPLs I have mentioned, could you illustrate those commands?
I am working inside of a project using RVM to manage the gemset, and would like to not modify that environment at all, maybe only my general terminal environment, if possible.
.blank? is from ActiveSupport. You can actually just load ActiveSupport without the rest of Rails:
irb(main):001:0> require 'active_support/all'
irb(main):002:0> [].blank?
=> true
The all.rb file loads all of ActiveSupport.
The same can be done with ActiveRecord and other rails components; for example:
irb(main):001:0> require 'active_record'
=> true
irb(main):002:0> class NewModel < ActiveRecord::Base; end
=> nil
irb(main):003:0> NewModel.new
ActiveRecord::ConnectionNotEstablished: No connection pool for NewModel
This gives an error because I didn't bother setting up a database, but it shows that Rails is pretty modular. I've used ActiveRecord in projects without Rails (the rails gem is actually an empty gem which just defines the various active_* gems as dependencies).
Most of the Rails "magic" come from Active Support Core Extensions. You can include that in a regular irb session to get most of the connivence methods like blank?.
Start an IRB session and run
require 'active_support'
require 'active_support/core_ext'

Rake FileTask rebuilds despite :intemediate => :phony

Problem
I am trying to use phony tasks in Rake, to prevent forced rebuild of my FileTasks.
(Exerpt from ruby/lib/rake/phony.rb on GitHub)
# Defines a :phony task that you can use as a dependency. This allows
# file-based tasks to use non-file-based tasks as prerequisites
# without forcing them to rebuild.
Despite using the :phony task, my FileTasks still rebuild. I have made an example demonstrating this.
Example Scenario
We need to build final.file from source.file, using an :intermediate task.
It should only rebuild if final.file is out of date with source.file. However, listing :intermediate as a prerequisite, forces a rebuild every time.
Using rake/phony and the :phony task as a prerequisite is supposed to fix that, but doesn't.
Example Code:
require 'rake/phony'
task :default => 'final.file'
file 'final.file' => ['source.file', :intermediate] do |f|
touch f.name
end
# Marked as phony, so should not force FileTask to rebuild
task :intermediate => [:phony] do |t|
puts "#{t.name} task"
end
Problem Demonstation
$ touch source.file # Create the source file
$ rake # Run Rake to build 'final.file'
intermediate task
touch final.file
$ rake # Rake should NOT rebuild, but does. <<<<<<<<
intermediate task
touch final.file
Version
As you can see, I am using a more recent version of Rake than the one which introduced phony tasks (which was 0.9.4), so :phony should work.
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]
$ rake -V
rake, version 10.4.2
I guess rake/phony is a gem? It's not something built into rake, I don't think, I've never seen it before.
Maybe this one? https://github.com/floere/phony But that seems like it might have nothing to do with what you're talking about, so maybe that's not it, and you are using something else.
Whatever it is you are using, you could try posting an Issue on their github, or otherwise asking them a question if their readme has other preferred methods of receiving questions. It might be a bug in that gem, or maybe that gem doesn't do what you expect.
It's likely few readers here are familiar with that gem, and at any rate don't have the interest to read your lengthy post/question where you paste a huge chunk of source code.
Since we don't know what it is or what it's supposed to do, we don't really have a way to know if it's a bug in that gem or if you're doing it wrong, and while there are lots of people on the internet who enjoy helping out by answering a targetted question on something they are familiar with, there are very few who enjoy going through a vaguely worded "Am I doing something wrong or is it broken?" question that pastes in gigantic swathes of source material, on something they are not familiar with.
I think lib/rake/task.rb has a broken definition of "timestamp" method.
Here is what I think it should be:
def timestamp # on Task
prerequisite_tasks.collect { |pre| pre.timestamp }.max || Time.now
end
I found this information in this page:
http://blog.zenspider.com/blog/2012/01/simulating-phony-in-rake.html
So one hack to fix it is to re-open the Task class and redefine the timestamp method like so:
require 'rake/phony'
task :default => %w[targetA]
file targetA: :test do |t|
sh "touch #{t.name}"
end
task :test do |t|
p t.name
end
task :test => :phony
class Rake::Task
def timestamp
prerequisite_tasks.collect { |pre| pre.timestamp }.max || Time.now
end
end
I guess rake/phony is a gem? It's not something built into rake, I don't think, I've never seen it before.
No, it's part of Rake:
https://github.com/ruby/rake/blob/master/lib/rake/phony.rb
It can be used only for File tasks, as a dependency, so that Rake stops complaining that it doesn't know how to build that dependency.
A basic usage example:
require 'rake/phony'
file "doc.html" => "doc.md"
file "doc.md" => :phony
This is taken from an actual Rakefile I use:
require 'rake/phony'
LIB_ES_SOURCES = FileList['alan_en/StartLib/*.i']
LIB_ES_SOURCES.each do |lib_src|
file 'alan_en/cloak/cloakv3.a3c' => "#{lib_src}"
file lib_src => :phony
end
where I need every *.i in the alan_en/StartLib/ folder to depend on the status of the alan_en/cloak/cloakv3.a3c (a compiled VM file); but then Rake would complain that it didn't know how to build all those .i files, hence the line that creates a File task for each .i file, making it dependent on :phony.
Once you require 'rake/phony' the :phony task is immediately available, and you can assign it as the dependency of any File task. It will never require executing the task since its always mimicking an up to date status, so it won't execute any custom code either (it's what its name indicates: a dummy/phony/fake task).

Tracing dependency loading in Rails

Our team is working on a new application that we started with Rails 3.1 and Ruby 1.9.2 - and last night I took it to Ruby 1.9.3.
One of the gems we were using in the dependency chain (css_parser) ended up having a require 'iconv' in it, triggering a deprecation warning in 1.9.3 that looked like this:
.../gems/activesupport-3.1.1/lib/active_support/dependencies.rb:240:in `block in require': iconv will be deprecated in the future, use String#encode instead.
At first I naively blamed that on rails without a better trace, until I didn't find a require 'iconv' in it anywhere.
The only way I tracked this down was that I started commenting things out in my Gemfile and then I finally got the bright idea to load irb and start requiring each library in turn. I also could have just done a filesystem grep in the gems directory, but I wasn't exactly sure that "require 'iconv'" was what was triggering the error.
What a PITA. There has to be a better way - just doing a --trace in rake tasks that load rails didn't cut it. Is there some way / any way of triggering a trace on this that would have shown me which line in the relatively long list of library dependencies was triggering the deprecation?
So, it's probably a little moot because I'm not likely to ever run into the problem again (and the css_parser gem was the only iconv-requiring gems in my current Rails 3.1/Ruby 1.9.3 projects).
But it was a puzzle, so I wanted to find some way of solving it.
The problem is very iconv-specific in this case. There are other ruby deprecations, but for the most part they seem to go through Kernel#warn (if ruby) or rb_warn() (if C) - but the warning in iconv.c is a little different than the others - at any rate it's a puts to rb_stderr.
So maybe I can do the following
Override Kernel#require to capture stderr
Check for an iconv message after calling the original Kernel#require
Raise an exception if the message found, thereby getting a trace
Do this before bundler runs if at all possible.
It turns out I can't do #4 - because Bundler calls Kernel.require directly - but I can use Bundler to parse the Gemfile to give me a list of things to require myself.
So this is what I get - thanks to this stack overflow post for a pointer on capturing standard error - and the rubygems source for the idea on aliasing the original Kernel#require
# override Kernel#require to intercept stderr messages on require
# and raise a custom error if we find one mentioning 'iconv'
require "stringio"
class RequireError < StandardError
end
module Kernel
alias :the_original_require require
private :the_original_require
def capture_stderr
# The output stream must be an IO-like object. In this case we capture it in
# an in-memory IO object so we can return the string value. You can assign any
# IO object here.
previous_stderr, $stderr = $stderr, StringIO.new
yield
$stderr.string
ensure
# Restore the previous value of stderr (typically equal to STDERR).
$stderr = previous_stderr
end
def require(name)
captured_output = capture_stderr do
the_original_require(name)
end
if(captured_output =~ %r{iconv})
raise RequireError, 'iconv requirement found'
end
end
end
require 'bundler'
# load the list of Bundler requirements from the Gemfile
required_libraries = Bundler.definition.dependencies.map(&:name)
# loop through and require each, ignoring all errors other than
# our custom error
required_libraries.each do |requirement|
begin
require(requirement)
rescue Exception => e
if(e.class == RequireError)
raise e
end
end
end
And voila! A trace message that helps track down where the iconv requirement was.
In the end, probably just a search for "require 'iconv'" is still best (once it's clear that's the what was causing the error).
But, as in life. Some Yaks Must Be Shaved.
You could take a look at the Gemfile.lock file, which holds all dependencies in a hierarchical tree and indicates the versions required by each gem. This might help to identify the gem that is requiring it.

Active Merchant - uninitialized constant ActiveSupport::XmlMini_REXML::StringIO

I have activemerchant 1.16.0 and rails 3.0.5.
I am trying to build a basic code to communicate with PayPal's gateway using active merchant.
if credit_card.valid?
# or gateway.purchase to do both authorize and capture
response = gateway.authorize(1000, credit_card, :ip => "127.0.0.1")
if response.success?
gateway.capture(1000, response.authorization)
puts "Purchase complete!"
else
puts "Error: #{response.message}"
end
else
puts "Error: credit card is not valid. #{credit_card.errors.full_messages.join('. ')}"
end
I get the following error:
/Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/xml_mini/rexml.rb:20:in `parse': uninitialized constant ActiveSupport::XmlMini_REXML::StringIO (NameError)
This error propagates from the gateway.authorize() call.
Any idea what's wrong with my setup?
Thanks.
According to the question, it doesn't work when the code is by itself, but works when require "stringio" is added.
My suspicion is that ActiveMerchant is unit-tested, but for some reason the dependency on StringIO isn't detected by those unit tests, possibly because other parts of the unit testing code indirectly requires stringio.
One thing I recently found out was that require 'yaml' gives you the stringio library as a side effect:
StringIO.new
# NameError: uninitialized constant StringIO
# from (irb):1
require "yaml"
# => true
StringIO.new
# => #<StringIO:0x7fb7d48ce360>
RUBY_VERSION
# => "1.8.7"
and it wouldn't be hard to imagine unit tests for ActiveMerchant (or other parts of Rails) requiring yaml.
However, this is only speculation. I haven't checked, as I don't use Rails.
Andrew Grimm pretty much hit the nail on the head with his original comment on this question. The missing require 'stringio' is indeed the issue. But it is a bug with Rails, more specifically ActiveSupport 3.0.9 (which is where the error seems to be coming from). We can trace it down using the git commit history of rails.
First we need to check out rails and switch to the v3.0.9 tag. If we now look at activesupport/lib/active_support/xml_mini/rexml.rb we see that require 'stringio' is not there. In and of itself this is not significant, but bear with me. We can now switch to the next tag (v3.0.10.rc1), and we'll see that the file hasn't been updated (it is likely that this version of rails will have the same issue). Next tag in line is v3.1.0.beta1, notice that this time around there is a require 'stringio' at the top of the file.
We can check out the commit that brought in this change (this one here from Jan 19th 2011). The commit message says:
fixed a missing require that causes trouble when using AS in a
non-rails env
This would indicate that as long as you're in a rails environment this issue wouldn't surface. So, my guess is something about the environment caused the issue to come up, may have something to do with the fact that the OP says they are using rails 3.0.5, but the error is coming from activesupport-3.0.9. Perhaps the code was called from a rake task that forgot to inherit from :environment (difficult to say without more info). Either way, putting require 'stringio' at the top of the code is definitely the fix, until you can upgrade to Rails 3.1 (once it comes out) at which point the require will no longer be needed.

How can I override a method in a ConnectionAdapter class in Rails 3 for use in a rake task?

In order to override the table_exists? method in the Rails PostgreSQL adapter I have tried the following in an initializer file:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
def table_exists?(name)
raise 'got here'
end
end
This will raise the the following error:
uninitialized constant ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
I believe this would have worked in previous versions of rails and I even found a small plugin that did something like this in Rails 2.3.6. Also I only encounter this error when I am trying to run a rake task like db:migrate and not when I start my application server.
Could someone show me the right way to do this and / or explain why PostgreSQLAdapter doesn't seem to be loaded when I am in an initializer file?
Instead of config/initializers, place that code in lib/ folder.
While this means that the active_record is loaded after the rails initializers, which is unusual. I ll update this with more detail, once I am done investigating the whole flow. If you want some more details about the rails 3 initialization process, check out this link:
http://ryanbigg.com/guides/initialization.html
I had success by moving this code into a Rails plugin. It is a little bit more overhead, but it is working consistently when I run rails s and when I run rake db:migrate.
I just followed the rails guide page on the topic and ran
rails generate plugin rails_patches --with-generator
and moved my init.rb file into rails as recommended.
~vendor/
`~plugins/
`~rails_patches/
|~lib/
| `-rails_patches.rb
|~rails/
| `-init.rb
|+test/
|-install.rb
|-MIT-LICENSE
|-Rakefile
|-README
`-uninstall.rb
I put this code in init.rb:
require 'rails_patches'
I put this code in rails_patches.rb:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
def table_exists?(name)
raise 'got here'
end
end
This now behaves as I expected.

Resources