Atomic conditional counter update with ActiveRecord in Rails without transaction

Yes there is Table.update_counters(record.id, :my_counter => by_count) . But that’s not conditional – for example I want to update counter only if result will be >= 0. Atomically.

You can try something like

but it’s not really atomic operation (unless you wrap in transaction with row lock, which I don’t like).

And if you try this

you will find it doesn’t really care about the where condition and it ignore it.

So what can I do? Right, I’m not, surprisingly, limited to predefined Rails methods but I have whole Ruby and ActiveRecord to act as my slave, not master. Little instance method in my model definition will do the job:

Let me know what would you improve in comments ;)

RSpec and DatabaseCleaner: Using different cleaning strategy per example

Sometimes you need to use different cleaning strategy for particular test example than transaction. But setting deletion or truncation for whole test suite could result in huge slowdown. Here’s how to solve it:

Usually you have something like this in your spec/rails_helper.rb file:

As you may see there is example objected passed to the around hook of rspec. This object looks like regular Proc object pointing to the example test block. But it actually carry some meta information about the example itself and it’s context in example.metadata value, like name, test description, test file, etc.

Simply we could just match test name against tests we want to use different strategy and set it for them. But it would not be so DRY. Fortunately, RSpec allows to specify custom parameters for each example, context, describe block and so, that are inherited by test hierarchy. Lets use it for setting specific cleaning strategy:

and change around hook configuration of DatabaseCleaner:

Happy testing! :)

Ruby on Rails – Internal redirect and render of action from another controller

You probably need to render action from other controller than the one currently processing user’s request and you don’t want to redirect user’s browser. Just in case, make sure you know why you want it :)

I need it because I want to render my 404 and 500 error pages (which I handle throught routes) but I don’t want to raise exception that will be handled so far in ShowExceptions middleware which makes notification in Airbrake which has middleware just bellow it.

So my solution is to create simple middleware placed just above my application which will play request/response ping pong with it as long as the application want to redirect somewhere else. To make this condition I used headers list returned from application to middleware on top of it. When application return respond with X-Internal-Redirect-To header, my middleware throws the request back to the application just with changed PATH_INFO environment variable.

Code

Here is implementation of middleware class. Save it somewhere to your lib folder, eg lib/internal_redirect.rb

Then add it to middleware stack of your application. To do that change your config/application.rb file:

Add require for create class file at the top of application.rb file:

And add ocnfiguration directive

After that, try run “rake middleware” command. “use InternalRedirect” should show up just above the application.

Use it

To use internal redirect, just use “head” method of Action Controller in your actions:

That’s it. Enjoy :)

Cropping image to aspect ratio with ImageMagick in Rails

I wanted to crop image in paperclip to some aspec ratio so that cropped image will use full width or height of original image.

A little bit math

It is simple to see that if croping is “wider” than original image, it must crop top and bottom of image and use full width. Otherwise, if cropping is “taller” than original image, it crops left and right while using full image height. This can be luckilly computed simply like this:
Let r_c is ratio of width:height of desired cropped image and r_i is ratio of original image.
If r_c > r_i (wider) then cropped image should have width = original_width and height = original_width / r_c
Otherwise, if r_c <= r_c (taller) then it should crop to width = original_height * r_c and height = original_height.
Problem is that it needs to know aspect ratio of original image. Retrieving that information somehow before hand is quite complicated and ineffective moreover since ImageMagick always know it. Can’t it do that computation by its own? ImageMagick never stops surprising me, yes, it can do that. Let’s look on it:

Convert options

It’s Ruby syntax, but it should be understandable :)

Example

Original image:
Chucky-Childs-Play
With ratio = 2 (width = 2* height):
chucky_crop2
With ratio = 0.5 (height = 2* width):
chucky_crop05