duck_punching

Ruby, Rails and tech. No ducks were harmed in the making of this blog.

Archive for the 'rails' Category

Passenger (mod_rails) for development. Now with debugger!

Dev mojo

After reading the great posts by Geoffrey “PeepCode” Grosenbach and Manfred Stienstra about using Phusion Passenger for development I had to give it a try. My doctor she’d never heard of mod_rails but gave me antibiotics for it just in case.

After little bit of setup I can say I am much happier with this dev rig than the old ‘script/server’ style. Just open a browser and the app is just waiting to serve you. Nice and agile or something.

Bugger no debugger!

One thing was missing for me though. With no –debugger switch to play with, I needed an alternative. Fortunately the brilliant ruby-debug has the solution with remote debugging. The tricky part was turning remote debugging on or off easily so we didn’t destroy our new dev mojo with onerous meddling in an environment file.

Keepin’ it real (easy)

So your working away and you run into a tough bug in some action or corner of your app. You need to break out the debugger. So the most straight forward way I have found is doing this

rake restart DEBUG=true

But how does it work. Here is a little something I prepared earlier.

In the style of passenger’s restart.txt the restart task also creates debug.txt in the tmp folder if the DEBUG switch is set to true.

Then in development.rb we look for the debug.txt file which triggers ruby-debug to be loaded. We set the ‘wait_for_connection’ option to true which gives us a chance to connect to the remote debugger when the app restarts. Finally start the debugger and clean up the debug.txt file.

From here you refresh the browser and it will it get stuck loading the page. This is because the app is waiting for you to connect to the remote debugger session. In a terminal type

rdebug -c

Once its running you can add and remove debugger statements in the code without needing to restart the debugger or the app. Now you just use the debugger as normal.

If you close the terminal or exit the debug session you can’t reconnect with it. You must do a restart with the DEBUG switch again. Once you cancel the debug session the app won’t drop into the debugger when it hits ‘debugger’ statements any more. So you can continue as normal until you need the debugger again and do a restart.

There you go, thats pretty neat and tidy and agile and whatever.

UPDATE:
I should probably mention that for ease of use and efficiency when using ruby-debug in remote mode you should probably use the ‘set autoeval’ setting. To do that create a file called .rdebugrc in your home directory and put this these lines in for good measure:

set autoeval
set autolist
set autoreload

Follow this link for more info on these settings.

36 comments

Run plugin specs/tests with gem or vendored rails

When I create a plugin I set up the tests or specs to be able to run stand-alone, that is not inside Rails app. But when you want to try the plugin out inside a real app, it can help to be able run the specs against vendored version of Rails if the application has one.

So to neatly auto-detect if the plugin is in an app with vendored Rails and to use that Rails for testing, I hacked this little snippet

vendored_rails = File.dirname(__FILE__) + '/../../../../vendor/rails'
if File.exists?(vendored_rails)
  Dir.glob(vendored_rails + "/**/lib").each { |dir| $:.unshift dir }
else
  gem 'rails', "=#{ENV['VERSION']}" if ENV['VERSION']
end

This checks for the Rails folder in vendor with extra care by going up to where the app root would be and down through ‘vendor/rails’, rather than directly to the rails. If a vendored Rails is found it puts each module’s parent folder at the front of the load path to make sure its used ahead of the gems.

For a bonus it also allows you to specify a version of the Rails gem if you want, by setting the VERSION parameter on the command line, when not inside an app.

Afterwards you just require the Rails parts you need as usual.

require 'active_support'
require 'active_record'

If the vendored rails exists the the libraries are required from there, otherwise the gems are used. Stick it in the top of your test or spec helper.

No comments

ar_mailer gem forked on GitHub, goodies added

Now that GitHub has a gem server it allows the process of managing your own fork or customisation of a gem ridiculously easy. No need for your own gem server or shipping around gem files, just put it up on github and nominate it as a gem in the project config. GitHub will automatically compile the gems using a gemspec file if present. All the info you need is here so I won’t recap it any further.

A gem which I find essential for Rails apps which send out emails is ar_mailer by Eric Hodel of Seattle Ruby Brigade and Ruby Hitsquad fame and now the maintainer of RubyGems. But there a couple of things missing. One is the need for pid files to be generated when running as a daemon to allow effective management with monitoring tools and such.

Well there just so happened to be a patch by Dylan Egan in the ar_mailer forums to add this feature, but it has been overlooked for a long time. So I thought this would be a good chance to fork it and use the GitHub gem system as well. Its now forked it and patched with some tweaks to get it working and a few fixes for the tests which broke due to changes in the latest ZenTest gem.

The project for the gem is here. To use the new gem you need to remove the old one because of the way github names your gems. It uses github username as a prefix to the gem name. This means the old gem will be loaded instead of the new gem when required in your app. But the binary will be used from the new gem causing nasty problems.

To install, first add GitHub as a gem source

sudo gem sources -a http://gems.github.com

Then

sudo gem install adzap-ar_mailer

Now when the binary is run in daemon mode you will get the pid file you need. You can specify the pid file location in the command options like so

ar_sendmail -d -p ./log/ar_sendmail.pid

Any relative paths are expanded from the app directory. You can of course use an absolute path if you wish. The file gets removed on exit as you would expect.

The other major addition is not as visible. Its a Ruby based init.d script for managing mailer startup for one or more apps. It uses a yaml based config file where you specify the app settings for each app that needs a mailer instance running. See the README and demo config for more info.

Ruby, my hammer, is starting to make everything look a nail!

Remember this is GitHub, don’t like what I have done, then fork off!

UPDATE:
If you are getting an error running the ar_sendmail binary, this is due to GitHub to setting the permission on gem binary files incorrectly. The error would be

/usr/bin/ar_sendmail:19:in `load': no such file to load -- ar_sendmail (LoadError)
	from /usr/bin/ar_sendmail:19

To fix it you need to run this ugly (please let me know a better way to get a gem path!!)

GEMS_PATH=`gem env path`
GEM_NAME='adzap-ar_mailer'
sudo chmod 755 $GEMS_PATH/gems/$GEM_NAME*/bin/*

Now you should be able to execute it as a normal user.

UPDATE 2:
Fixed the update fix and made it version non-specific

UPDATE 3:
GitHub fixed the file permissions issue so the work around is not needed anymore.

2 comments

Using ActionView in standalone tests

When writing Rails plugins I like to be able to test them as a stand-alone library rather than inside a specific Rails project. I find it more productive and it avoids clashes with other plugins. It also allows you to test it against multiple rails versions.

One frustration I have had is when just want to use ActionView in your tests, because you might be writing a view plugin, if you require ‘action_view’ you get the following error:

MissingSourceFile: no such file to load -- html/document

This is because the path to the html-scanner library has not been added to the loadpath. This only happens in ActionController. But if we don’t need or want the overhead of ActionController the following line will include html-scanner in the loadpath and all will be well.

$:.unshift Gem.searcher.find('actionpack').full_gem_path 
  + '/lib/action_controller/vendor/html-scanner'

This finds the actionpack gem to get the full path. Then with the path to the html-scanner folder, adds it to the loadpath ($:). Now no more pesky load errors.

If there is a cleaner way, let me know.

2 comments

calendar_helper plugin forked

I have been using Geoffrey Grosenbach’s calendar_helper plugin and needed a few changes. I am also using git for projects now and finding the submodule a workable strategy for plugins. So I imported it into git using git-svn and created a new project on GitHub. I plan to do some refactoring to make it a little cleaner but mostly will just tweak for my own usage.

My first changes were to remove the requirement for the year and month to be passed in as options. These now default to the current month and year if not included in the options hash.

I have also added the :month_name_text option to override the default text for the month name. The month name is basically the calendar header so this makes it possible to include the year in the header for clarity.

Now that I have forked it, I removed the gem spec files as it will not be published as a gem as that would confuse everyone and just isn’t the done thing.

Feel free to use and fork of course, these are just my preferences and maybe more to come. Thanks of course go to the original authors and contributors of the plugin.

No comments

Passing a block to ActiveRecord create

I submitted a patch for Rails, which has been committed, to allow you to pass a block to the AR create class method. It got a mention on the RailsEnvy podcast in the Living on the Edge section.

It mind sound boring, but it allows you to pretty up the regular code such as creating a new record from the parameters hash to then save it.

Often you might

@person = Person.new(params[:person])
@person.set_status :alive
@person.group = "default"
@person.save

now you can pretty it up with

@person = Person.create(params[:person]) do |p|
  p.set_status :alive
  p.group = "default"
end

The inner workings are that it creates a new object using the hash and then passes the object into the block for further manipulation. After the block is executed the record is saved and returned.

It can be particularly useful if you have a few protected attributes that you need to set or some instance method you need to execute when you are creating a record. Admittedly the set_status method might best be run as a callback in the model, but you get the idea.

It also works for the array variant of create when you pass in an array of hashes. The code in the block is executed for each record.

So look for it in Rails 2.1 or use it now with Edge.

Footnote: The original patch was actually larger and included the update method as well. Though DHH was not in favour of it, mentioning that the class update method itself may be of dubious value.

1 comment