“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey (contact@robl.me)
Senior Software Engineer, Brighton, UK

ActiveRecord::MultiparameterAssignmentErrors

interesting bug, ever heard of this one ActiveRecord::MultiparameterAssignmentErrors?

So, on your social networking site the person signing up want’s to expose their birthday so they can get loads of best wishes but is a bit conscious of their age.

>> Person.new("born_on(1i)" => "", "born_on(2i)" => "4", "born_on(3i)" => "25")
ActiveRecord::MultiparameterAssignmentErrors: 1 error(s) on assignment of multiparameter attributes

This has only occured ocassionally, not everytime someone doesn’t want to set their year of birth.

born_on(1i) : year
born_on(2i) : month
born_on(3i) : day

>> Person.new('born_on(1i)' => '2012', 'born_on(2i)' => '12', 'born_on(3i)' => '12').born_on
=> Wed, 12 Dec 2012
>> Person.new('born_on(1i)' => '', 'born_on(2i)' => '12', 'born_on(3i)' => '12').born_on
=> Thu, 01 Dec 0012

It turns out the assignment gets really confused when it is nil, or at least when the first interger is nil it removes it and sets the first integer it finds to the year, the second to the month and the third…well it sets it to 1, or the first of the month. How annoying. I would have hoped you could validate against assigning incomplete dates, but apparently not.

This breakdown from Thoughtbot demonstrates the process they took to not really solve this problem. Ultimately they used a work around; a before_filter in the controller.

http://robots.thoughtbot.com/post/159808527/ruby-on-fails

def validate_expires_on
    Date.new params[:job]['expires_on(1i)'].to_i,
    params[:job]['expires_on(2i)'].to_i,
    params[:job]['expires_on(3i)'].to_i
  rescue ArgumentError
    params[:job].delete 'expires_on(1i)'
    params[:job].delete 'expires_on(2i)'
    params[:job].delete 'expires_on(3i)'
  end

I guess a before_filter that matches all (i) params could be put in an application wide before_filter to cover every case like this, if arises.