Multiplay Labs

tech hits and tips from Multiplay

Archive for July, 2009

Rails belongs_to breaks attribute assignments

without comments

So belongs_to and other auto associations in rails are a great time saver, until they break and prevent attribute assignments that is 🙁

So here’s an example of the problem:-

# created_state_id = 1
# published_state_id = 2
post = Post.new( "my post", "stuff..." )
post.state = created
post.save
logger.info "Post saved: #{post.state_id}"
....
logger.info "Before update: #{post.state_id}"
post.state_id = published_state_id
logger.info "After update: #{post.state_id}"
post.save
logger.info "After save: #{post.state_id}"

You would expect that after the second save that post.state_id would be 2 yes? Well its not; the output from the above would be:
> Post saved: 1
> Before update: 1
> After update: 2
> After save: 1

So what’s the deal? The problem is that the assignment to post.state before the first post.save call flags the association, in BelongsToAssociation, as updated but this updated flag is never cleared even after save, so after that point its impossible to change the value of state_id via direct assignment.

Quite a serious issue really as information is lost. The only way to avoid this is to only ever assign using either the association or the attribute i.e. don’t mix and match the two.

I’ve raised this as part of the bigger update issue when changing attributes that are the pk of an association so keep your eye on: Rails issue #142: belongs_to association not updated when assigning to foreign key

Written by Dilbert

July 24th, 2009 at 6:47 pm

Posted in Hackery,Rails

Rails Spawn in production mode = missing log entries

with 2 comments

When running under passenger in production mode ( which uses buffered logging ) when an error occurs in a task / process which is created using Spawn the log messages are lost. This is due to the call to exit! in spawns fork_it method.

The following patch fixes this and a few more minor issues

--- vendor/plugins/spawn/lib/spawn.rb.orig      2009-07-22 20:27:51.000000000 +0100
+++ vendor/plugins/spawn/lib/spawn.rb   2009-07-22 20:37:02.000000000 +0100
@@ -17,7 +17,7 @@
     if !env || env == RAILS_ENV
       @@method = method
     end
-    @@logger.debug "spawn> method = #{@@method}" if defined? RAILS_DEFAULT_LOGGER
+    @@logger.debug "spawn> method = #{@@method}"
   end
 
   # set the resources to disconnect from in the child process (when forking)
@@ -103,7 +103,7 @@
         # run the block of code that takes so long
         yield
 
-      rescue => ex
+      rescue Exception => ex
         @@logger.error "spawn> Exception in child[#{Process.pid}] - #{ex.class}: #{ex.message}"
       ensure
         begin
@@ -116,6 +116,8 @@
           end
         ensure
           @@logger.info "spawn> child[#{Process.pid}] took #{Time.now - start} sec"
+          # Because we use exit! we must try to ensure the log is flushed else output including errors could be lost
+          @@logger.flush if @@logger.respond_to?(:flush)
           # this form of exit doesn't call at_exit handlers
           exit!(0)
         end

Written by Dilbert

July 22nd, 2009 at 8:19 pm

Posted in Hackery,Rails

Debugging Rails: Rails application failed to start properly

without comments

Having spent the entire of today chasing a problem with rails, running under passenger, where it always erroring for specific URL’s with: “Application Error” “Rails application failed to start properly” I thought I’d share one very useful tip which identified the problem me, so hopefully it will save other hours of head banging.

./scripts/console
>> app.get '<Problem URL>'

Now if this is a problem with most parts of your app the error will be plain to see, instead of being caught up in the hand off between passenger and apache resulting in the less than useful Application Error.

N.B. Another good indication that this will help is the existence of “Premature end of script headers” errors in your apache log file.

Written by Dilbert

July 6th, 2009 at 5:19 pm

Posted in Hackery,Rails

perl Makefile.PL errors with “Unable to find a perl 5” on cygwin

without comments

When trying to build a new module on one of our machines which runs cygwin the basic command perl Makefile.pl failed with the error:

Unable to find a perl 5 (by these names: perl.exe perl.exe perl5.exe perl5.8.0.exe miniperl.exe, in these dirs: /usr/local/bin /usr/bin /bin /usr/X11R6/bin /usr/local/libexec/apache /usr/local/bin /usr/bin /bin /usr/X11R6/bin /cygdrive/c/WINDOWS/system32 /cygdrive/c/WINDOWS /cygdrive/c/WINDOWS/System32/Wbem /cygdrive/c/Program /bin /usr/bin)

After doing some digging this turned out to be a simple permissions issue on the perl.exe although perl scripts would happily run in perl -x /usr/bin/perl.exe was returning false.

The fix was a simple chmod a+x /usr/bin/perl.exe for anyone who comes across this issue.

Written by Dilbert

July 4th, 2009 at 1:29 pm

Posted in Hackery,Perl

Ruby URI.parse being strict results in URI::InvalidURIError

without comments

When using ruby’s URI.parse yesterday I was getting URI::InvalidURIError on what seemed to be a perfectly valid URI. After much digging in the source and reading the URI RFC 2396 and subsequent 3986, I discovered that the reason for this is that URI.parse applies this RFC strictly, so where a number of applications are quite happy to provide and use URI’s containing the “unwise” characters, URI.parse doesn’t accept them and throws a URI::InvalidError.

Fear not though there’s a really easy fix, just replace the direct call with:

myuri = URI.parse( URI.encode( uri_string ) )

This does however raise the question: Should parse implicitly call encode?

Written by Dilbert

July 2nd, 2009 at 8:36 am

Posted in Code