Wednesday 6 June 2007

ruby on rails params and empty strings

A little annoyance I've found using ruby on rails is the following:

If in your model you have some strings that can be null, and the user doesn't fill the related fields in the web form, rails will end up storing an empty string "" instead of the good old NULL in the database.

Now, this is for sure not a big problem but it has some implications that might affect the model validations and it can be even worse if the rails app is not the only program writing in the database, in this last case you easily end up with a mix of empty string and NULL values in the column making trickier to write queries conditions that involve that column.

Now I was playing today to fix this problem and I came with a solution that uses SimpleDescriptor.

For any model that uses SimpleDescriptor as described in this post the following is a way to have NULL saved in the database instead of the empty string ''

first you need to define the clean_strings method


def clean_strings
self.class.described_as(:string).each do { |field| send("#{field}=", nil) if send(field) == '' }
end


and then add the clean_strings method in your before_validation callback


before_validation :clean_strings


Starting from this moment your model will just save NULL instead of an empty string and the :allow_nil => true in the model validations will start behaving as expected.

Monday 4 June 2007

Simple Descriptor, code less validate more

After 6 month I've released a new version of Simple Descriptor.

This gem makes possible to attach some extra informations to a generic ruby class, but its mission is now includes specific methods to allow more control and flexibility on ActiveRecord validations, in addition to this, Simple Descriptor may help you in building a consistent approach in areas where rails doesn't.

Let's start getting our hands dirty, first of all install the gem


sudo gem install simple_descriptor


after that you need to require the gem i.e in your config/environments.rb file

require 'simple_descriptor'


now let's tweak our Employee ActiveRecord model

the migration to create the Employee model will be

class CreateEmployees < ActiveRecord::Migration
def self.up
create_table :employees do |t|
t.column :first_name, :string, :limit => 30, :null => false
t.column :middle_name, :string, :limit => 10, :null => true
t.column :last_name, :string, :limit => 30, :null => false
t.column :gross_wage, :integer, :null => false
t.column :personal_email, :string, :limit => 100, :null => false
end
end

def self.down
drop_table :employees
end

the basic model definition will be

class Employee < ActiveRecord::Base
end

to get some validations for free we need to add 2 lines of code

class Employee < ActiveRecord::Base
extend SimpleDescriptor::ClassDescriptor
validates_ar_descriptions
end

These 2 extra lines will

  • validates_presence_of every field defined as NOT NULL

  • validates_length_of every field defined with a limit

  • validates_numericality_of every field defined as anumber


but there some extra as well, fire the console of your rails app and type

Employee.described_as :string

this will return all the fields defined as string in the database.
Now always in the console try

Employee.maxlegth(:first_name)

this will return 30 which is the maximum length of the first_name field

Or again you can have the list of the required fields

Employee.described_as :required
=> [:first_name, :gross_wage, :last_name, :personal_email]


Or you can ask your model if specific field is required

Employee.describes? :first_name as => :required
=> true

If you want to inspect a bit more what's happening behind the scenes you can use

Employee.descriptions

Now, let's say you have some different models i.e. Employee, Manager, Consultant and in all these models you have some sensible fields you want to show only to authorized people.

If you use Simple Descriptor for all these models you can easily define which fields contains sensible informations, for the Employee it would be


class Employee < ActiveRecord::Base
extend SimpleDescriptor::ClassDescriptor
validates_ar_descriptions
describe :gross_wage as => :sensible
end

Starting from this moment you can ask the Employee class if a field is sensible or not

Employee.describes? :gross_wage, :as => :sensible
=> true

Employee.describes? :first_name, :as => :sensible
=> false

Or you can obtain the list of sensible fields

Employee.described_as :sensible
=> [:gross_wage]

This may help you to manage sensible data show rules in your views or in your controller.

To know more about Simple Descriptor you can just visit the online docs