Ahh, noen ganger blir jeg litt ekstra fornøyd når jeg ser hvordan enkle grep i Ruby gjør småting som i utgangspunktet skurrer mye bedre. Ikke at det er spesielt avanserte ting, men dette gjør at jeg sover litt bedre om natten:

I Flere i bilen har jeg et par modeller Route og RouteSearch. Reisen (Route) har attributtene mandag, tirsdag, onsdag, torsdag, fredag, lørdag, og søndag. På reiser kan det krysses av for hvilke dager de kjøres og følgelig blir korrespondere dager satt til true. I Reise-modellen gjøres også disse dagene tilgjengelige for masse-tilordning via attr_accessible, og jeg har lagt på mulighet for å hente ut for eksempel alle reiser som går på mandager med Route.mondays via named_scope. En liten hjelpefunksjon svarer på om noen dager er valgt i det hele tatt. Denne funksjonaliteten er definert ca som følger:

class Route < ActiveRecord::Base
  DAY_ATTRIBUTES = [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday]

  attr_accessible *DAY_ATTRIBUTES

  DAY_ATTRIBUTES.each do |day|
    # Oppretter mondays, tuesdays etc, SQL condition monday = true
    named_scope day.to_s.pluralize, :conditions => {day => true}
  end

  def any_days_selected?
    DAY_ATTRIBUTES.each {|day| return true if send("#{day}?")}
    false
  end

  # mer kode her..
end

Som nevnt har jeg et par modeller, og modellen som står for Reisesøk har også ukedager som attributter. Når mandag blir satt til true på et reisesøk vil route_search.routes kun returnere reiser som kjøres på mandager osv. Et reisesøk skal også ha dagene tilgjengelig via masse-tilordning, den skal kunne svare på om en eller flere dager er valgt i det hele tatt og det kan godt ha funksjonalitet så jeg kan hente ut alle Reisesøk som søker etter reiser på mandager. Med andre ord er funksjonaliteten til de to modellene når det gjelder ukedager like. Det enkleste løsningen, men samtidig den som bør få folk til å sove dårligst om natten, er litt klipp og lim. En annen mulighet kunne vært via arv, men en reise og et reisesøk er strengt tatt ikke en type av den andre.

Ruby støtter moduler der funksjonalitet kan grupperes og etter en liten ommøblering (noen som har et godt ord for refactor?) i koden ser Route-klassen nå slik ut:

class Route < ActiveRecord::Base
  include CommonBehaviourForWeekdays
end

class RouteSearch < ActiveRecord::Base
  include CommonBehaviourForWeekdays
end

Mye bedre enn klipp og lim! ..og hva har vi i CommonBehaviourForWeekdays?

module CommonBehaviourForWeekdays
  DAY_ATTRIBUTES = [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday]

  module HelperMethods
    class << self
      def attach_named_scope_for_day_names_on(base)
        DAY_ATTRIBUTES.each do |day|
          base.named_scope day.to_s.pluralize, :conditions => {day => true}
        end
      end

      def make_days_attr_accessible_on(base)
        base.attr_accessible *DAY_ATTRIBUTES
      end
    end
  end

  # Hook som blir kjørt når denne modulen blir inkludert
  def self.included(base)
    HelperMethods.attach_named_scope_for_day_names_on base
    HelperMethods.make_days_attr_accessible_on base
  end

  def any_days_selected?
    DAY_ATTRIBUTES.each {|day| return true if send("#{day}?")}
    false
  end
end

Vi har nå delt samme funksjonalitet over flere klasser, men samtidig holdt implementasjonen av denne funksjonaliteten på ett sted.