Tuesday, February 13, 2007

Rails 1.2 and rb-gsl ruby math lib don't play nice together!

Hi,

so Rails 1.2 might be nice, but I got some HUGE headaches when migrating to Rails 1.2. This time, all my ActiveRecord objects were raising a "private method `equal?' called for #" exception when I was using require 'gsl' no matter were in my code. That sucks a lot because ruby is a slow language (yet powerful) so I really needed to use the C native maths (matrix stuff) functions from rb-gsl.

With Rails 1.1.6 everything was OK, but with Rails 1.2, I started to get errors like:

private method `equal?' called for #
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/core_ext/class/inheritable_attributes.rb:127:in `inherited_without_layout'
/usr/lib/ruby/gems/1.8/gems/actionpack- 1.13.2/lib/action_controller/layout.rb:185:in `inherited_without_helper'
/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.2/lib/action_controller/helpers.rb:120:in `inherited_without_api'
/usr/lib/ruby/gems/1.8/gems/actionwebservice- 1.2.2/lib/action_web_service/container/action_controller_container.rb:84:in `inherited_without_action_controller'
/usr/lib/ruby/gems/1.8/gems/actionwebservice-1.2.2/lib/action_web_service/dispatcher/action_controller_dispatcher.rb:32:in `inherited'
./script/../config/../app/controllers/application.rb:6


The problem with ruby is that each framework attempts discretely to do its own magic by redefining existing methods. But frameworks end up crunching themselves this way. That's pretty much the same knd of trouble I had with gettext (see previous post)

After looking quite a while at the code, I had no idea what object was this Hash:0xb74e20fc object neither why ActiveSupport would care about it. Adding some debug logs into ActiveSupport, I saw that all GSL objects are being handled by ActiveSupport but again, I found no way to prevent such a nasty exception to occur.

At the end, I found a dirty compromise to continue using rb-gsl in my Rails app:

First it implies you patch ActiveSupport (1.4.1 in my case) to look if the method 'equal?' isn't private as it would just occur with rb-gsl:
add this method visibility check line 127 of
/usr/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_support/core_ext/class/inheritable_attributes.rb

if (!inheritable_attributes.private_methods.index('equal?')) && inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)

(hint: you can use that check to log the problematic 'child' object if you want to debug Rails or rb-gsl)

Second, we can't require 'rb-gsl' inside an ActiveRecord object (neither a module included in an ActiveRecord object) anymore because even if we avoid the first illegal access to the private method, a there is a second catch that would break out later: 'can't change a frozen Hash', go understand...

So you'll have to encapsulate your rb-gsl lib inside some wrapping ruby object that will contains require 'gsl' and provide ruby methods to the gsl methods you are interrested in. And eventually your controllers or ActiveRecord object will play with that wrapper to call the gsl math functions.

Yes, overall, doing that really sucks, does anyone have a better idea? Who is the culprit? Rails or rb-gsl? If rb-gsl, how modify it to make it Rails compliant again?

NB: Paul King also noticed this bug with rb-gsl:
http://rubyforge.org/pipermail/mongrel-users/2007-January/002659.html
but he could eventually add a stub empty equal? method to its problematic object. This didn't work at all in my case though.

Friday, February 09, 2007

Rails 1.2 doesn't play nice with gettex

Hi,

After migrating to Rails 1.2, under certain conditions, I had suddenly lots of trouble to save any trivial ActiveRecord object. All was working like a charm before and with Rails 1.2, I started to get that exception:
In the console, I play with a dummy ActiveRecode model with only one sample string field:

>>foo=Foo.new
>>foo.save
>>foo.save SystemStackError?: stack level too deep
from
...
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.1/lib/active_record/connection_adapters/abstract/database_statements.rb:59:in `transaction' from /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.1/lib/active_record/transactions.rb:95:in `transaction' from /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.1/lib/active_record/transactions.rb:121:in `transaction' from /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.1/lib/active_record/transactions.rb:129:in `save_without_validation' from /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.1/lib/active_record/validations.rb:752:in `save'


By under certain conditions, I mean that the bug was hardly consistent, it happened only after I my application gained some complexity (Foo excepted) and also using the auth_generator plugin.

Still, I think the problem is coming from gettext (1.9.0) that seems to not behave correctly with Rails 1.2. In any situation, removing gettext always removed that bug.

So in my case I hope gettext deveoppers will react while I'm polishing my app business logic, else I'll be forced to migrate to Globalize.

Hope this helps.

Raphaël.

Prototype 1.5 bug?, at least not backward compatible with auth_generator...

Hi,

I recently upgraded my web app to Rails 1.2 coming along with Prototype 1.5. Also, In that app, I'm using the auth_generator plugin, a wonderfull plugin allowing to create a user base + login system + right policy in a snap. But what makes it very special is that this Rails plugin can display users info in a javascript generated DOM fragment that will behave accordingly to the user specific cookie allowing you to cache all your pages statically, and that's really a big win considering how slow ruby is compared to hitting only Apache for static pages.

Ok, but this is not the point. The point is that auth_generator has got some simple Ajax requests and they do not work anymore with Prototype 1.5 at least with Firefox (2.0.0.1 on Ubuntu Linux Edgy)!
Here is an example of such a request:
new Ajax.Updater('accountinfo', 'http://localhost:3000/auth/logout', {asynchronous:true, evalScripts:true, onLoading:function(request){Element.show('ident_spinner')}}); return false;")
Nothing especiall as you can see (Or please tell me if I'm wrong).
But this freezes on a Prototype exception arround the line 916:

[Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXMLHttpRequest.setRequestHeader]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: http://localhost:3000/javascripts/prototype.js?1170853340 :: anonymous :: line 916" data: no]


I have no idea at all what should be the correct behavior, if that's a Prototype bug, a Firefox bug or an auth_generator bug.

I have no idea of what side effect this could have, but a dummy fix for me consisted in rewritting the lines arround line 916 this way:

for (var name in headers) {
try {
this.transport.setRequestHeader(name, headers[name]);
} catch (e) {
//do nothing
}
}


Hope this helps, if you have a better fix, please go on and comment.

Raphaël

Update: OK, Prototype 1.5 really bombs out with Firefox, others railers discovered the bug and they found no other fix, see here:
http://dev.rubyonrails.org/ticket/6918