I don't know if we've been missing out on deliberate API lovin' or that we're becoming dumber every minute because of too much work, or its just the love month? :) ...but we've been missing the power of "toggle".
Toggle is defined as:
any instruction that works first one way and then the other; it turns something on the first time it is used and then turns it off the next timeNeedless to say, toggle is very efficient for use with boolean values (defined by either true or false). Let's take a specific scenario:
create_table "profiles", :force => true do |t|
t.string "salutation", :limit => 8, :default => ""
t.string "name", :limit => 200, :default => ""
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "themes", :force => true do |t|
t.integer "profile_id",
t.string "name", :limit => 100, :default => ""
t.boolean "primary", :default => false
end
So, there are multiple themes per profile. You should get at least that part. Your boolean column should always be set to false by default. Either you replace the name of your column to suit that requirement, or write dirtier code. (I.e., instead of have a "public" column all set to true, use "private" column all set to false by default). Now, of course, your associations should be setup properly similar to:
class Profile < ActiveRecord::Base # filter_chain methods here... # validations here... # associations start... has_many :themes do def primary find(:first, :conditions => ["primary = ?", true])
end
end
# associations end...
end
class Theme < ActiveRecord::Base # filter_chain methods here... # validations here... # associations start... belongs_to :profile # associations end... named_scope :current_theme_of, lambda { |profile| { :conditions => [ "profile_id = ? and primary = ?", profile.id, true ] }
}
end
Of course, there would be several records for the Theme table that will belong to a profile. You will offer a checkbox on every create and update of the themes of a particular profile, but how do you ensure that there will only be one primary theme set for each profile record?
This is dirty: (KIDS, DO NOT TRY THIS AT HOME)
class Theme < ActiveRecord::Base # filter_chain methods here... after_save :verify_unique_primary_theme # validations here... # associations start... belongs_to :profile # associations end... named_scope :current_theme_of, lambda { |profile| { :conditions => [ "profile_id = ? and primary = ?", profile.id, true ] }
}
def verify_unique_primary_theme
# get all themes by this profile
# set all their primary value to false
# set this new one's primary value to true
end
end
Man, I wouldn't bet on a quick update on a profile whose set of themes would be more than hundreds, or even thousands! This, of course, is always worth a try:
class Theme < ActiveRecord::Base # filter_chain methods here... # validations here... # associations start... belongs_to :profile # associations end... named_scope :current_theme_of, lambda { |profile| { :conditions => [ "profile_id = ? and primary = ?", profile.id, true ] }
}
def primary?
primary
end
def validate
#ensure that primary true is for one record only
if primary? and !profile.themes.primary.nil?
#toggle the old primary theme of this said profile
profile.themes.primary.toggle!(:primary)
end
end
end
Simple, yet it works! Each time another theme gets toggled to be the primary theme, you only need to make two writes to your database:
- Save your new item
- Flip the old primary to false
I hope this toggle magic works for you too the next time you think about boolean switches!
:)