Some Rails / Ruby tricks you should know 1

Posted by kain Mon, 25 Aug 2008 04:17:00 GMT

Grab column names for a model with magic fields and primary key stripped out

>> Dictionary.content_columns.collect { |col| col.name }
=> ["it", "en"]
# or
>> Dictionary.content_columns.map(&:name)
=> ["it", "en"]

Get an ActiveRecord Model attributes

>> Dictionary.first.attributes
=> {"it"=>"ciao", "id"=>1, "en"=>"hello"}

Discover which column yields the data you’re looking for

>> Dictionary.first.attributes.index("hello")
=> "en"

Take out some given keys from an Hash easily

# I think rails should need a method similar to content_columns and attributes_names but for extracting content_values
>> Dictionary.first.attributes.except("id")
=> {"it"=>"ciao", "en"=>"hello"}

Remove all whitespace on both ends of a string, change multiple spaces into one

" foo   bar    \n   \t   boo".squish # => "foo bar boo"

Manage repetitive find conditions via a Hash

# Basic
>> Model.find(:all, :conditions => ['first_name LIKE :name OR last_name LIKE :name', {:name => "aname"}])
# Extended example
# available_languages is a method which returns an Array.
>> word = "hello"
>> conditions = [ Dictionary.available_languages.collect { |language_column| language_column + ' = :word' }.join(" OR "), { :word => word } ]
>> Dictionary.find(:first, :conditions => conditions)

Not really a rails feature but you can append methods to the "end" block

    query_string_array.inject('') do |string_so_far, current_word|
      string_so_far + ' ' + lookup_word_and_build_translation_string(current_word)
    end.squish

Returns an array with the names of the subclasses of a class

# This works in production mode or development with config.cache_classes =  true or when classes are loaded
>> Account.send(:subclasses).map { |o| o.to_s } # this is protected in AR
# or
>> Object.subclasses_of(Account).map { |o| o.to_s }

Build up a sentence from an array taking advantage of the new I18n rails adapter, without last comma

# This will also use the "connector" word you defined in your language, default for en-US is "and".
>> %w(a b c).to_sentence(:skip_last_comma => true)
=> "a, b and c"
# Add in your language file:

  # Used in array.to_sentence.
  support:
    array:
      sentence_connector: "e"

There’s a ton of other stuff, just browse Active Support files to find much more useful and time-saving extensions. Now go refactor your code and make it even more prettier :)

More on i18n, active record error messages

Posted by kain Thu, 21 Aug 2008 18:53:00 GMT

Meanwhile I’m waiting for some fixes to be tossed in into rails core (YAML files instead of ruby for example), here’s how to translate your active record error message in rails edge using the new i18n framework.

 

I18n.backend.store_translations "it-IT", {
  :active_record => {
    :error_messages => {
      :inclusion => "non è incluso nella lista",
      :exclusion => "è riservato",
      :invalid => "è invalido",
      :confirmation => "non coincide con la conferma",
      :accepted  => "deve essere accettata",
      :empty => "non può essere vuoto",
      :blank => "non può essere vuoto",
      :too_long => "è troppo lungo (il massimo è {{count}} lettere)",
      :too_short => "è troppo corto (il minimo è {{count}} lettere)",
      :wrong_length => "è della lunghezza sbagliata (deve essere di {{count}} lettere)",
      :taken => "è già in uso",
      :not_a_number => "non è un numero",
      :greater_than => "deve essere superiore a {{count}}",
      :greater_than_or_equal_to => "deve essere superiore o uguale a {{count}}",
      :equal_to => "deve essere uguale a {{count}}",
      :less_than => "deve essere meno di {{count}}",
      :less_than_or_equal_to => "deve essere meno o uguale a {{count}}",
      :odd => "deve essere dispari",
      :even => "deve essere pari",
      :can_only_contain_letters_and_numbers => "può contenere solo lettere e numeri"
    }
  },
  :yes => "sì",
  :no => "no"
}

Custom validation message example:

  validates_format_of :username, :with => /^\w+$/i, :message => :can_only_contain_letters_and_numbers