Posts about Rails

validates_as_phone on GitHub

August 9th, 2008

A second plugin to GitHub today.

validates_as_phone is a Ruby on Rails plugin that provides strict validation for phone numbers. At the moment, only phone numbers in Australia are supported. This will still be extended to support classifications and areas in the future.

validates_as_phone
==================

Strict validation module for phone numbers that supports classifications and
areas.

= General usage

== Installation

You can install the plugin the traditional way. Go to your application root
and do:

  script/plugin install git://github.com/kristinalim/validates_as_phone.git

== Validate your model attributes

Example:

  class Person < ActiveRecord::Base
    validates_as_phone :phone, :allow_blank => true, :set => true
  end

= License

Written by Kristina Lim (http://i-think.com.ph/kristina/)

Copyright (c) 2008 Syndeo Media
http://syndeomedia.com

= Contributing

If you wish to contribute to the project, you may contact the author through:

'kristinasyndeomediacom'.insert(8, '@').insert(20, '.')

= Acknowledgements

This plugin is named after the validates_as_phone plugin of Jerrod Blavos
(http://code.google.com/p/validates-as-phone/). Admittedly, this plugin was
built over the latter, but as the purposes of this plugin is more complex than
that of the minimal one, practically all of the code has been written over by
now.

schedule_attribute on GitHub

August 9th, 2008

I pushed schedule_attribute to GitHub early today.

The Ruby on Rails plugin schedule_attribute provides support to ActiveRecord for a Data Definition Language (DDL) for schedules.

schedule_attribute
==================

Provides support to ActiveRecord for a Data Definition Language (DDL) specific to schedules.

= Language

A datetime pair comprised of the start datetime and end datetime is defined with two lines. At the moment, only one option is available.

== Weekly Schedule

  mon 09 00 ==> Monday, 7 AM
  01 17 00  ==> Monday, 5 PM

  1 00 00   ==> Monday, midnight
  2 05 00   ==> Tuesday, 5 PM

  5 09 00   ==> Friday, 9 AM
  0 09 00   ==> Subday, 9 AM

= General Usage

== Installation

You can install the plugin the traditional way. Go to your application root and do:

  script/plugin install git://github.com/kristinalim/schedule_attribute.git

== Specifying the Attributes for Schedule

In your models, you can do:

  class Person < ActiveRecord::Base
    schedule_attribute :office_hours, :type => :weekly
  end

== Checking if a Datetime is Within the Schedule

  person.within_schedule?(:weekly, :office_hours, Time.now)

= License

Written by Kristina Lim (http://i-think.com.ph/kristina/)

Copyright (c) 2008 Syndeo Media
http://syndeomedia.com

= Contributing

If you wish to contribute to the project, you may contact the author through:

'kristinasyndeomediacom'.insert(8, '@').insert(20, '.')

Processing Globalite language files

March 30th, 2008

Projects that support several languages often have centralized lists of string translations for each language that they support. In the case of the Globalite plugin, these translates would be in YAML files. By default, of course. Within the views themselves, translatable strings would be replaced by symbols, and each of these symbols would supposedly have a corresponding key-value mapping in each language file.

Dealing with translations without a straightforward system for managing duplicates and additions to the files would commonly require removing duplicate key mappings in a file, finding duplicate key-value mappings between two files, and finding key mappings in one file that are not in a second file.

Hurray, the YAML library:

# Load YAML
require "yaml"

# Load language file to a hash. Hashes store only one value for a key, so if
# there are more than one declarations for a key in a single file, only the
# last one is used.
en_us = YAML::load("lang/ui/en-US.yml")
de_de = YAML::load("lang/ui/de-DE.yml")

# Find common key-value mappings between two files.
duplicates = Hash.new
en_us.each_pair  do |key, value|
  if de_de[key] == value
    duplicates[key] = value
  end
end

# Find key declarations in one file that are not in a second file.
missing = Hash.new
en_us.each_pair  do |key, value|
  if de_de[key].nil?
    duplicates[key] = value
  end
end

# Write hash to YAML file.
File.open("new.yml", "w") do |out|
  YAML.dump(yaml_hash, out)
end

@geodist through Ultrasphinx

February 24th, 2008

For most of our projects over at Syndeomedia, we have been using Andrew Aksyonoff’s Sphinx search engine to handle the search functionality, and Evan Weaver’s Ultrasphinx Ruby on Rails plugin to serve as an API to the search daemon. Sphinx is an incredibly efficient full-text stand-alone search engine that has the ability to gracefully handle large bulks of data, while Ultrasphinx brags a configurator that can automatically generate a Sphinx configuration file from specifications in the models themselves. Ultrasphinx also handles generation of the actual result objects with extras, of course.

Sphinx/Ultrasphinx served our purposes together perfectly until we needed to sort some search results according to the distance between the objects that they represent and a varying location in order to increase relevance of the search results. The search engine actually already handles @geodist computations (and sorting), but there seems no way to do this with Ultrasphinx. While it is relatively easy to sort all search results, which would later be paginated, through a MySQL query, and even more convenient when using the :origin specifier from the GeoKit plugin, doing these involve incredible overload, especially if the application is dealing with more than just a thousand rows.

Now, both projects are relatively young, and I can imagine how the Ruby on Rails plugin always has to hurry after changes in the search engine. I got myself a bit more familiar with Sphinx and Ultrasphinx (and Pat Allen’s Riddle plugin, which Ultrasphinx uses), and made a few changes.

Patch anchor_support_added_to_search:

Index: lib/ultrasphinx/search/internals.rb
===================================================================
--- lib/ultrasphinx/search/internals.rb (revision 1701)
+++ lib/ultrasphinx/search/internals.rb (working copy)
@@ -18,6 +18,7 @@
           @offset = opts['per_page'] * (opts['page'] - 1)
           @limit = opts['per_page']
           @max_matches = [@offset + @limit, MAX_MATCHES].min
+          @anchor = opts['anchor']
         end
           
         # Sorting
@@ -329,4 +330,4 @@
     
     end
   end
-end
\ No newline at end of file
+end
Index: lib/ultrasphinx/search.rb
===================================================================
— lib/ultrasphinx/search.rb (revision 1701)
+++ lib/ultrasphinx/search.rb (working copy)
@@ -103,7 +103,8 @@
       :weights => {},
       :class_names => [],
       :filters => {},
-      :facets => []
+      :facets => [],
+      :anchor => {}
     })
     
     cattr_accessor :excerpting_options

Simple. Riddle already supports use of anchors. What the patch does is just allow the anchor to be set in the Riddle client instance that Ultrasphinx::Search instantiates.

If the anchor is set for the search session and the "extended" sort_mode is used, @geodist already becomes available for use in the sort_by declaration. Below would be an example of a search that would sort matches according to @geodist primarily, and name secondarily:
@search = Ultrasphinx::Search.new(:query => "east", :class_names => ["branch"], :per_page => 20, :page => 3, :sort_mode => “extended”, :sort_by => “@geodist asc, name asc”, :anchor => {:latitude_attribute => “lat”, :longtitude_attribute => “lng”, :latitude => degrees_to_radians(user.location.lat), :longtitude => degrees_to_radians(user.location.lng)})
@search.run(false)

Yes, that is “longtitude”.

:-) I hope this saves people some time.