No Comments »

Hello there,

it’s late in Bremen, so I will keep this thing as short as possible: I just wasted the complete day’s work at Tansporter due to a bad preparation… dumb me! (Remember: Benchmark before any optimization!)

I tried to optimize some of our ActiveRecord find statements, installed a whole new column on a table solely for that reason, changed the model to fill this new column right and then changed the actual method I would like to spice up.

It was a 70 line monster of very ugly code. After refactoring it, there were just 40 lines left and it was very cool, clean and beautiful code. The main change: I replaced a find statement which returned a very huuuuge result set, which I had to iterate and do some computing on every element, with 4 very cool queries with just one result, each.

Sounds cool, but unfortunately it isn’t.

After I had a short “wow, that’s great stuff!” experience, I thought it might not be unclever to benchmark the new method and compare it to the old one.
And here comes the trouble: The old method finished in about 0.018 seconds, the new one needed somewhat between 0.54 and 0.4 seconds… What a pitty!

So I switched back to the ugly version, to my rescue the added column could be used elsewhere so my effort was not completely useless.

What I’ve learned: One query with a large result set apparently performs MUCH better than 4 (not absolute trivial) queries with a very small result set, even if you have to iterate through the whole big result set.

Anyway I stumbled upon two cool, small things today that are worth mentioning them:

1st: Get a random “thing” out of the database.

Until today we managed this with a method at the particular model looking somehow like this:

1
2
3
4
5
6
7
8
9
10
  def self.random_good
    good = nil
    while (!good)
      begin
        good = Good.find(rand(Good.maximum(:id)))
        rescue ActiveRecord::RecordNotFound => e
      end
    end
    good
  end

Today I received my copy of The Rails Way and one of the first things I found was the native, MySQL “ORDER BY RAND()” function. Pretty cool. Because database portability doesn’t really matter for us, the same function as above now looks like this:

1
2
3
  def self.random_good
    Good.find(:first, :order => 'RAND()')
  end

2nd: Don’t forget about the power of ActiveRecord’s :include option!

The :include option of a find statement is very powerful! I read about this maybe a year ago, never needed it again and forgot about it. Today I rediscovered the veeeeery nice nesting capability:

1
2
  tickets = Ticket.find(:all, :include => [:user,
      {:operator => {:open_tickets => :user}}])

I can’t really believe it, but after this find statement you can do this:

1
  tickets.first.operator.open_tickets.last.user.nickname

…without ANY extra query! It’s all joined together in the one find query and still runs at a reasonable pace.

Ok, now it’s really time for me to go to bed.

Stay tuned,

Thorben
FEtMab-Team

No Comments »

Hi again,

the time has come to “release” our first Rails plugin! *wooooooooah*

It’s mission is really simple: Do things “in” a Rails application periodically, in the background. Ok, sounds like a perfect job for cronjobs? Yes, it is. But let me explain this:

We are just two guys, coding all day long. Server administration is not our favorite sport and we do not have a cool admin guy to keep things going. Due to that, we once had a cronjob running which we didn’t monitor as we should’ve. The end of the story is, that our job was not executed for 2 weeks until we recognized it.

So, cronjobs may be just perfect, but we really don’t want the extra pain of monitoring an extra tool and keep the crontables up to date with every deployment and so on. Our solution:

StupidBackground

Ohhh yes my dear, there are plenty of Ruby and/or Rails tools out there that do that background job thing very well: BackgrounDRb, BackgroundFu and much more cool tools. But while some of these tools just are too much for our needs (BackgrounDRb), the other tools, which are simple enough, do not cover exactly what we wanted to do (BackgroundFu): Periodically call some methods which calculates things and then stores them to the database.

So that’s when StupidBackground comes into play.

It’s sooo stupid, that even 5 year olds should immediately know how to use it. But just in case your mind is somehow different to that of a 5 year old, I’ll try to explain it for you anyway:

1. Install it

script/plugin install \ http://svn.fetmab.net/svn/plugins/stupid_background/tags/0.1.1

2. Code your worker

Just create a new class in “lib/workers” which inherits from “StupidBackground::Worker” like this:

1
2
  class FiveYearOldFighter < StupidBackground::Worker
  end

Now just add some methods to this. When these methods are called by StupidBackground they are in a complete Rails environment created by “script/runner“. So feel free to use any models or whatever classes you like to use within your application. Like this:

1
2
3
4
5
6
7
8
9
  class FiveYearOldFighter < StupidBackground::Worker
    def fight(quantity, victory_chant)
      puts victory_chant if FiveYearOld.find(
          :all, :limit => quantity, 
          :order => "badass_rank DESC").all? {|five_year_old|
              five_year_old.fight
          }
    end
  end

Last open question: How can we configure how often we would like to fight 5 year olds? It’s easy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  class FiveYearOldFighter < StupidBackground::Worker
 
    #THE NEXT TWO LINES ARE THE MAGIC!
    call(:fight).every(1.hour).with(20, "What a fight!")
    call(:fight).every(10.minutes).with(5, "Eaaasy one!")
 
    def fight(quantity, victory_chant)
      puts victory_chant if FiveYearOld.find(
          :all, :limit => quantity, 
          :order => "badass_rank DESC").all? {|five_year_old|
              five_year_old.fight
          }
    end
  end

To stay trained we now fight five 5 year olds every ten minutes and every hour we’re in the mood to fight 20 of them at the same time! Cool.

3. Start the background magic

Just one last thing to do:

rake background:start

And if you fought enough 5 year olds:

rake background:stop

Oh, and if you’ve forgotten if you’re right now fighting some 5 year olds try this:

rake background:status

That’s it. Pretty simple, but it is enough for our needs. Maybe this plugin is of some use for you.

Behind the scenes

StupidBackground uses the Daemonize library from Travis Whitton, tiny but great! This fact also means, that StupidBackground will not work on Windows machines.

The background behavior is realized via a stupid script/runner call, it’s not high sophisticated but again: it fits our needs.

The execution of the tasks happens in an non sophisticated way, too: StupidBackground just determines how long it is until the next task needs to be run, then sleeps this periods and then runs the job.

So if you have one job which should run in 5 seconds and another job which should run in 6 seconds, the first job runs in 5 seconds and when it’s finished the second job runs. So the intervals which you specify in a worker are not accurate enough for brain surgery… You have to see them as rough intervals which works, you guessed it already: great for us.

Any worker is just instantiated once! So if you would like to share informations between two jobs in the same worker you easily can. But be aware of unattended side effects, when one method saves information in an instance variable and another job reads it, even if it should not! The simplest way to get around this is to outsource any logic from your worker and then write two workers which both use the outsourced code.

If you would like to overwrite the initializer of the worker ensure that your initialize method takes one argument and passes this to the super initializer:

1
2
3
4
  def initialize(method)
    #your stuff
    super(method)
  end

Somehow like this.

Summary

  • Periodically, task execution in a Rails application, in the background.
  • No gems needed.
  • No extra YAML or any other configuration. Anything is configured within your workers.
  • One instance per worker, NOT per job.
  • No threading if two jobs should run at the same time! Just waiting for one to finish, then starting the other.

Ok, I hope this is of some help for some of you. Feel free to add comments.

Yours,

Thorben
FEtMab-Team

No Comments »

While it is always good to have attr_accessible or attr_protected set in a ActiveRecord model class to protect it from abuse when updating any object of that class from the params of a Rails controller.

But what to do when you have that attr_accessible but you won’t let a certain action in your controller even edit all of those accessible fields. Maybe because you’re paranoid or just a think that an action should only be allowed to edit what they was invented for, there might be some good reasons.

We faced this problem lately and came up with that solution:

1
2
3
4
5
6
7
8
9
10
11
12
class ActiveRecord::Base
  def update_by_params(params, *fields)
    self.attributes = params.reject
        {|key,value| !fields.index key.to_sym}
    self.save
  end
  def update_by_params!(params, *fields)
    self.attributes = params.reject
        {|key,value| !fields.index key.to_sym}
    self.save!
  end
end

The update_by_params instance method on the ActiveRecord::Base class let you do something like this:

1
2
3
4
5
6
# ... in a controller ...
def change_password
  @current_user.update_by_params(params[:user],
      :password, :password_confirmation)
  redirect_to frontpage_url
end

And then the user won’t be able to edit his address with a hacked password change form, even if he is allowed to do so in his profile.

The method will save the object after the update. To handle errors on saving there are (as usual in Rails) two specifications of this method available, one with a ! at the end which just uses save! to save the object and one without the ! which uses save. So update_by_params! will throw an error if the save fails while update_by_params just returns false.

Have fun with that.

Yours,

Thorben
FEtMab-Team

No Comments »

Rails 2.0 will ship with a new ActionController class method called:

1
rescue_from Exception, :with => :method_name

…which will rescue all exceptions in actions, thrown when the application runs in production mode with the given method.

As I read that I thought: Why only in production mode? It seems the Rails team designed this tool to rescue exceptions that were not wanted to be thrown, but why?

In our newest application I had the problem that we wanted to be able to display e.g. a login box on several places all over the app.
We created a login box partial which displayed a form that posted the login to the login action at the user controller. But what if the login fails? We ended up with something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def login
  unless request.post?
    flash[:notice] = :login_failed
    redirect_to_last_page
    return
  end
  user = User.authenticate(params[:nickname], params[:password])
  unless user
    flash[:notice] = :login_failed
    redirect_to_last_page
    return
  end
  #doing the login stuff in session...
end

Mhm… two times the exact same unless block just with a different condition? Not very DRY, isn’t it?

Ok, we’re nearly there where this post started. Why not just throw a UserErrors::LoginFailed Error? This would look like this:

1
2
3
4
5
6
def login
  raise UserError::LoginError unless request.post?
  user = User.authenticate(params[:nickname], params[:password])
  raise UserError::LoginError(user) unless user
  #doing the login stuff in session...
end

Quite cool. Now we outsourced the things that should happen on a login failure to this private method in the user controller:

1
2
3
4
5
def login_error(e)
  flash[:notice] = :login_failed
  redirect_to_last_page
  return
end

And at to get this method work when a UserError::LoginFailed method is thrown we added this as private methods to the application controller:

1
2
3
4
5
6
7
8
9
10
alias old_rescue_action rescue_action
def rescue_action(e)
  key = @@rescue_exceptions.keys.find {|el| e.is_a?(el)}
  return old_rescue_action(e) unless key
  send(@@rescue_exceptions[key][:with], e)
end
 
def self.rescue_from_all(e, params)
  @@rescue_exceptions[e] = params
end

This let us now do this:

1
rescue_from_all UserError::LoginFailed, :with => :login_error

at the top of the user controller.

That’s all. If now a UserError::LoginFailed exception is raised in the controller it gets handled by the login_error method. Not quite a big deal but I like it.

If I find some time this week I will put this to a small plugin, so that you can give it a try even easier.

If you have any questions, or want do discuss if this is nifty or just crap, you’re welcome to leave your comment.

Yours,

Thorben
FEtMab-Team

No Comments »

It’s a pitty that I couldn’t be at the RailsConf Europe in Berlin. But the holidays weren’t that bad, either.

So as I discovered the first version of Davids keynote online today I couldn’t resist and had to watch this even if there actually was no time for and now I’m even writing this post…

But there’s one thing I saw in the video which I think it’s worth to be mentioned: What was “freaking awesome” a year ago is now “neat”. Seems something like Rails is leaving puperty.

Sure, I’m not the first who notices that, even David himself speaks about it at the beginning of his talk. But as I followed his talk I got more and more convinced, that he’s not only saying that Rails is now not a rebel any more, he is “living” that.

Rails has very fast gone a long way from rebellion to maturity and now really seems to be there.

It’s definitely a good thing and I hope with the Rails 2.0 release which seems to be more finetuning than turning anything upside down this maturity also gets spread to the decision makers who could not be convinced today.

I think Rails is still on a good way and this without airs and graces.

Let’s look forward to more Rails magic in the near and further future.

Thorben
FEtMab-Team