Double Shot #513
Spent too much time yesterday fighting with code. Hope to spend more time writing it instead today.
- What's New in Edge Rails: Cleaner RESTful Controllers w/ respond_with - More DRY coming for your views in Rails 3.0.
- Continuous Integration Spring Cleaning - More sysadmin from GitHub, including their own CI Joe continuous integration server.
- sqrbl - An ETL tool that takes its inspiration from Active Record migrations.
- MORE CUCUMBER - The only prescription for Rails development.
- Getting Ack to see HAML files - I needed this the other night.
Double Shot #512
Lots of people are excited about Rails and 37Signals being mentioned in Microsoft's annual Form 10-K. I think that's just silly. This isn't any sort of acknowledgement that Microsoft considers us a serious threat; it's a "cover your ass" survey of software and firms whose business overlaps that of Microsoft. For some perspective, go look at other 10-K's; for example, the one for McDonald's says "The Company’s competition in the broadest perspective includes restaurants, quick-service eating establishments, pizza parlors, coffee shops, street vendors, convenience food stores, delicatessens and supermarkets." So, yeah - McDonald's:street vendor::Microsoft:37 Signals. That'd be about right.
NoSQL: If Only It Was That Easy - Look at some of the currently-sexy database alternatives by someone who actually evaluated at heavy load.
Deployment Script Spring Cleaning - New ideas on using Capistrano with git, from the GitHub guys.
Napkee - Convert Balsamiq Mockups to HTML/CSS/JSS/Flex 3 source.
Lone Star Ruby Conference - One more week for registration for this Texas conference at the end of the month.
Cerberus 0.7 - Lightweight continuous integration, now with Bazaar support and better Git support.
RailsBridge BugMash - Contribute to the Rails core - Just a reminder: it's coming up this weekend.
complex-form-examples - Ryan Bates takes a shot at showing ways to manage forms with nested attributes.
va_cache - Simple caching for Active Record virtual attributes.
Double Shot #511
On the whole, I'm happy I picked Rails to switch to a few years ago.
- Introducing Hashdown - Rails plugin to provide hash-like access for ActiveRecord lookup tables.
- IE6 No More - Yet another attempt to stamp out the world's most hated browser.
- Bodega - Kind of like an app store for OS X desktop apps.
- urlagg - A delicious.com aggregator in Rails, notable because it comes with a full suite of cucumber tests.
- Ruby I don't like #2 - catch(:wtf) { throw :wtf } - Another fine rant from Pratik.
- Server Lining - Mysterious stealth announcement from Rubaidh, who do good stuff.
- Bowline - Crossplatform Ruby GUI framework built on top of Titanium (which in turn builds on Webkit).
- PostgreSQL, Rails, and why you should care - Pretty much sums up why I'm moving my own development over to PostgreSQL despite the learning curve.
Double Shot #510
I hope a lot of you are planning to participate in the Rails BugMash - it's shaping up to be a lot of fun.
- Psychology of Abundance and Creating a self-organizing environment - A couple of reports from last weekend's Ruby on Rails Outreach Workshop for Women, by Sarah Allen and Ilen Zazueta-Hall.
- Users and Passwords - Basic handling advice from Koz.
- Ruby I don't like #1 - Explicit 'return' - Pratik tackles a style issue.
- Book Review: Rails Freelancing Handbook - Noel Gomez tosses a few kinds words my way.
- phuby - PHP runtime in Ruby. Eek.
Double Shot #509
My latest production, released over the weekend: Rails Freelancing Handbook.
- cmon - Cutesy HTML preprocessor for columnar/tabular cross-browser layouts
- Bluefeather - Another alternative/extended Markdown converter.
- Bag O'Links - By the way, Elad Meidar is also doing a great link blog, in case Fresh Cup isn't enough for you.
- Installing And Using SQLite With Ruby On Windows - Helpful info for those getting started with Rails.
- Return of Ruboto! - IRB running on Android. Interesting even if I'll probably never need it for anything.
- Firefox/Namoroka - What's coming down the pike next now that 3.5 has shipped. Nightly builds are here if you want to live dangerously.
- lockrun - Tool to prevent cron from launching a new job if an old one hasn't completed yet.
Recurring Items in a Rails Application
I recently had to implement some recurring items in a Rails application - we'll call them "entries" here though you can use this technique for appointments, bills, or whatever else. After thinking about it for a while, I settled on:
Here's what I came up with. If your needs are different, you'll no doubt need to alter it. First, the schedule model has a schedule_type, an interval, a specific value, and a description. The combination of these things lets me implement
[sourcecode language='ruby']
class Schedule
has_many :entries
attr_accessible :schedule_type, :description, :interval, :specific
SCHEDULE_TYPE = {:first => 0, :last => 1, :weekly => 2, :monthly => 3}
def next_date(current_date)
case schedule_type
when SCHEDULE_TYPE[:first]
first_day = (current_date + 1.month).beginning_of_month
wday = first_day.wday
if specific >= wday
first_day + specific - wday
else
first_day + 7 + specific - wday
end
when SCHEDULE_TYPE[:last]
if specific == -1
(current_date + 1.month).end_of_month
else
last_day = (current_date + 1.month).end_of_month
wday = last_day.wday
if wday >= specific
last_day - wday + specific
else
last_day - wday - 7 + specific
end
end
when SCHEDULE_TYPE[:weekly]
current_date + interval.weeks
when SCHEDULE_TYPE[:monthly]
current_date + interval.months
end
end
[/sourcecode]
So we can have a schedule that is "first Monday of the month" or "every 3 weeks" among other things. I stock these up using db-populate; here's some of the population file:
[sourcecode language='ruby']
Schedule.create_or_update(:id => 1,
:schedule_type => Schedule::SCHEDULE_TYPE[:monthly],
:interval => 1, :description => "Every month")
Schedule.create_or_update(:id => 2,
:schedule_type => Schedule::SCHEDULE_TYPE[:monthly],
:interval => 2, :description => "Every other month")
Schedule.create_or_update(:id => 4,
:schedule_type => Schedule::SCHEDULE_TYPE[:weekly],
:interval => 1, :description => "Every week")
Schedule.create_or_update(:id => 8,
:schedule_type => Schedule::SCHEDULE_TYPE[:first],
:specific => 0, :description => "First Sunday of every month")
Schedule.create_or_update(:id => 15,
:schedule_type => Schedule::SCHEDULE_TYPE[:last],
:specific => 0, :description => "Last Sunday of every month")
Schedule.create_or_update(:id => 22,
:schedule_type => Schedule::SCHEDULE_TYPE[:last],
:specific => -1, :description => "Last day of every month")
[/sourcecode]
Then the entry model ties into the schedule model. Here are the important (for this purpose) bits of the entry class:
[sourcecode language='ruby']
class Entry < ActiveRecord::Base
belongs_to :schedule
named_scope :ready_to_recur, lambda { |date|
{:conditions => ["recurring = 1 AND next_date <= ? AND schedule_id IS NOT NULL AND next_created = 0", date ]} }
before_save :set_up_recurrence
def make_next_recurrence
if recurring? && !schedule_id.nil? && !next_created?
entry = Entry.create(
:entry_date => next_date,
:reference => reference,
:recurring => true,
:schedule_id => schedule_id
)
update_attribute(:next_created, true)
end
entry
end
def set_up_recurrence
if recurring? && !schedule_id.nil?
self.next_date = Schedule.find(schedule_id).next_date(entry_date)
self.next_created = false if next_created.nil?
end
true
end
end
[/sourcecode]
Finally, the whole thing is driven by a rake task that we run every night. This task finds all the entries that are ready to recur and creates the next entry:
[sourcecode language='ruby']
desc 'Create the recurring entries for today'
task :daily_recurring_entries => :environment do
Entry.ready_to_recur(Date.today).each do |entry|
entry.make_next_recurrence
end
end
[/sourcecode]
- At any point, we needed to know what the next recurrence date was.
- The potential schedules needed to be data-driven (because the client was unsure what would be needed).
Here's what I came up with. If your needs are different, you'll no doubt need to alter it. First, the schedule model has a schedule_type, an interval, a specific value, and a description. The combination of these things lets me implement
Schedule#next_date
to return the fate for the next date given a schedule object and the current date. Here's the model:[sourcecode language='ruby']
class Schedule
has_many :entries
attr_accessible :schedule_type, :description, :interval, :specific
SCHEDULE_TYPE = {:first => 0, :last => 1, :weekly => 2, :monthly => 3}
def next_date(current_date)
case schedule_type
when SCHEDULE_TYPE[:first]
first_day = (current_date + 1.month).beginning_of_month
wday = first_day.wday
if specific >= wday
first_day + specific - wday
else
first_day + 7 + specific - wday
end
when SCHEDULE_TYPE[:last]
if specific == -1
(current_date + 1.month).end_of_month
else
last_day = (current_date + 1.month).end_of_month
wday = last_day.wday
if wday >= specific
last_day - wday + specific
else
last_day - wday - 7 + specific
end
end
when SCHEDULE_TYPE[:weekly]
current_date + interval.weeks
when SCHEDULE_TYPE[:monthly]
current_date + interval.months
end
end
[/sourcecode]
So we can have a schedule that is "first Monday of the month" or "every 3 weeks" among other things. I stock these up using db-populate; here's some of the population file:
[sourcecode language='ruby']
Schedule.create_or_update(:id => 1,
:schedule_type => Schedule::SCHEDULE_TYPE[:monthly],
:interval => 1, :description => "Every month")
Schedule.create_or_update(:id => 2,
:schedule_type => Schedule::SCHEDULE_TYPE[:monthly],
:interval => 2, :description => "Every other month")
Schedule.create_or_update(:id => 4,
:schedule_type => Schedule::SCHEDULE_TYPE[:weekly],
:interval => 1, :description => "Every week")
Schedule.create_or_update(:id => 8,
:schedule_type => Schedule::SCHEDULE_TYPE[:first],
:specific => 0, :description => "First Sunday of every month")
Schedule.create_or_update(:id => 15,
:schedule_type => Schedule::SCHEDULE_TYPE[:last],
:specific => 0, :description => "Last Sunday of every month")
Schedule.create_or_update(:id => 22,
:schedule_type => Schedule::SCHEDULE_TYPE[:last],
:specific => -1, :description => "Last day of every month")
[/sourcecode]
Then the entry model ties into the schedule model. Here are the important (for this purpose) bits of the entry class:
[sourcecode language='ruby']
class Entry < ActiveRecord::Base
belongs_to :schedule
named_scope :ready_to_recur, lambda { |date|
{:conditions => ["recurring = 1 AND next_date <= ? AND schedule_id IS NOT NULL AND next_created = 0", date ]} }
before_save :set_up_recurrence
def make_next_recurrence
if recurring? && !schedule_id.nil? && !next_created?
entry = Entry.create(
:entry_date => next_date,
:reference => reference,
:recurring => true,
:schedule_id => schedule_id
)
update_attribute(:next_created, true)
end
entry
end
def set_up_recurrence
if recurring? && !schedule_id.nil?
self.next_date = Schedule.find(schedule_id).next_date(entry_date)
self.next_created = false if next_created.nil?
end
true
end
end
[/sourcecode]
Finally, the whole thing is driven by a rake task that we run every night. This task finds all the entries that are ready to recur and creates the next entry:
[sourcecode language='ruby']
desc 'Create the recurring entries for today'
task :daily_recurring_entries => :environment do
Entry.ready_to_recur(Date.today).each do |entry|
entry.make_next_recurrence
end
end
[/sourcecode]
Double Shot #508
A few odds and ends to close off the working week.
- QuickMagick - Another gem for use of ImageMagick by giving a ruby flavor to command-line operations.
- RailsLab: Scaling Your Database - Part 2 - The latest of Gregg Pollack's screencasts on scaling Rails.
- Working With Multiple Ruby Versions Has Never Been This Easy - Indeed, this looks like a simple way to install and switch between Rubies on OS X or Linux.
Double Shot #507
Wait, it's still July? This month may never end.
- acts_as_taggable_on_steroids was REALLY slow - A case where having some MySQL knowledge turned out to be critical.
- Embrace Technical Debt - An argument that sometimes writing sloppy code isn't such a bad thing to do.
- Freshlog - Screen capture for OS X that can automatically create Lighthouse or Unfuddle tickets from the result.
- Running Rails performance tests on real data - Pratik Naik explains how to do it.
- The 2009 GitHub contest - You too can help GitHub improve their algorithms.
Double Shot #506
Nothing like a busy day to cut down on my linking.
- URLAgg - Watch us work - Ever wonder what virtual pair programming looks like? Here's a longish unscripted session from Jeff Schoolcraft and Istvan Hoka.
- WindyCityRails - Early bird pricing for this Chicago-based conference is ending in just a couple of days, time to make up your mind.
- input_css - Rails plugin to automatically add sensible CSS classes to INPUT tags.
Double Shot #505
Looks like my August hours may be starting to fill out. That was a bit too close for comfort.
- The RailsBridge BugMash - Please do join us August 8-9 if you have any interest in improving the quality of Rails.
- Putting it all together - ResourceTemplates, described_routes and path-to - Plumbing to handle header-based discovery and easier client APIs.
- CheddarGetter - Subscription management and billing as a service.
- MySQL replication and Rails - A primer from Elad Meidar.
- The Ruty Template Engine - An alternative to liquid for adding customer-safe templates to Ruby-based applications.
- Pro Git - Scott Chacon's book on git is available in full under a CC license.
- Programmatically Creating Website Thumbnails - Guide from Rob Bazinet.
- Choosing a non-relational database; why we migrated from MySQL to MongoDB - Long article from the folks at Server Density.
Double Shot #504
I'm sure someone took the weekend off, but apparently it wasn't anyone whose site I read.
- Cucumber - The official Cucumber site is definitely spiffy these days. Makes me wish I found it to be a useful tool. Maybe I just haven't had the right exposure yet.
- Make your test suite UNCOMFORTABLY FAST! - Thoughtbot gets into the parallel testing act.
- Blackbird - Spiffy console logging for javascript.
- Git, Github, workflow questions - Nice discussion of git branching and deployment strategies, with input from the GitHub folks.
- time-warp - Gem to set the time to a pretend value for testing.
- How do I Flush DNS? - Includes instructions for doing so under OS X, which I recently needed.
- Talking to Wordpress with ActiveRecord - Just in case you need to do that.
- sqlite3-ruby 1.2.5 Released - Version bump, bug fixes, better compatibility for Windows & Ruby 1.9.
- Apple Push Notifications on Rails - Gem that should appeal to the growing overlap of people who do both Rails & iPhone work.
- yardstick - Tool to measure YARD (alternative to RDoc) coverage of ruby code.
Double Shot #503
This seems like a good time to remind folks that I've got time free for new and interesting Rails contracts, if you're looking to pick up an extra developer.
- rufus-tokyo 1.0.0 - This ruby library for Tokyo Cabinet hits a milestone.
Double Shot #502
Apparently delay was on people's mind yesterday.
- Do it Later With Delayed Job - Koz discusses the care and feeding of delayed_job.
- Backgrounded - Background Processing Done Right - Meanwhile, here's a new entrant in the background thread sweepstakes.
- Django 1.1 release candidate available - A week till release, barring major problems.
- Consuming OAuth Intelligently in Rails - Generator to make it easier for you to tie in to OAuth.
- Pixel Perfect - Firefox extension to overlay graphics on a developed site so you can see where you're off from what the designer intended.
Double Shot #501
Life goes on.
- Sunspot - Solr-powered search with Ruby syntax, including drop-in Rails integration.
- Major update to Ruby on Rails OAuth Plugin - Including conversion to a gem.
- My Thoughts on NoSQL - A reasonable look at some of the current contenders in the non-relational database world.
- Insurance on Rails - Some tips on rewriting legacy green-screen COBOL apps into Rails. Scary.
- Gestalt - Ruby and Python embedded scripts in web pages via Silverlight. No thanks.
- RubyGems 1.3.5 - Another version bump for gems. Looks like just a couple of small bug fixes.
- Redmine Kanban Plugin - Makes Redmine rather similar to Pivotal Tracker's one-page view of everything.
Double Shot #500
Yup, 500 of these things. A bit hard to believe.
- Rails 2.3.3: Touching, faster JSON, bug fixes - No huge changes, but some important fixes and a few minor features. The current plan is for 2.3.x to update every six weeks until 3.0 comes out.
- Better rake:routes - Better because it lets you specify a controller and only prints the matching routes if you do.
- Inquiry - Managed service to handle FAQs for your application. Not clear this is something I'd choose to outsource, but that appears to be the way of the future.
- constructor - Named argument style initialization for any Ruby class. Not new, but potentially useful.
- Ruby 1.9.2 preview 1 released - And the march of progress continues.
- What would you like in a code quality tool? - Cogent is planning a tool that you can just point at your repo. Fill out their survey for free access to the product when it exists.
- Git User's Survey 2009 - In case you'd like to offer the git developers some detailed feedback on your use of their tool.
Double Shot #499
Another productive weekend - may have a new project to announce shortly.
- What do we need to get on Ruby 1.9? - Wycats inquires. For me, the fact that I can't run a Rails app with a database using mainstream gems is a showstopper. Not interested in science projects when I'm trying to do paying work.
- Memcached 1.4.0 - Now released, including dead-simple Amazon EC2 AMIs for those who want to cache in the cloud.
- Nmap 5.0.0 released - I used port scanners a lot more when I was on Windows, but I still keep some eye at what's going on.
- Kii - A new entrant in the open-source Rails wiki sweepstakes.
- Test::Unit 2.0.3 - Huh, I hadn't realized T::U was still under active development.
- The Lazy developer: Tweak your MySQL - Elad offers some memory tuning suggestions.
- Big Old Rails Template - I've done some updating to this template, which I talked about here.
Double Shot #498
Early morning with small child and thunderstorms.
- Passenger/Nginx much better than Mongrel (at least for StatSheet) - Not clear how much of this is stack and how much is application style, but it's an interesting data point.
- The Great Ruby IDE Smackdown of '09 - Chad Woolley puts a few through their pages, and likes RubyMine.
- Critical JavaScript vulnerability in Firefox 3.5 - If you upgraded, you need to be aware of this. Personally, I run NoScript to squash such things.
- Five Features from Mercurial That Would Make Git Suck Less - Personally, I don't find git that sucky, but there are some useful ideas here from topfunky.
Double Shot #497
Up late deploying stuff last night, so just a couple of quick links this morning.
- snail - Start of an ambitious attempt to build a plugin to format international mailing addresses.
- Firebug 1.4.0 - Officially released, and nicer than 1.3. Of course those of us on the bleeding edge have moved to 1.5 alpha builds already.
Double Shot #496
It looks like the Fairy Godmother Department's lunch hour may be over.
- Many Ways to Tag Taggables - Tobias hunted down all the Rails tagging libraries he could find. Looks like he settled on acts_as_taggable_on, which is the one I use too.
- fleakr - Flickr API integration gem recommended by a couple of my readers.
- read_from_slave - Read your Rails data from a MySQL slave database, while ensuring that writes go to the master database.
- Programming Contest! Win iPhone 3GS & $2,000 Cloud Credit - Engine Yard is planning a contest that is going to make Twitter even more annoying for a while.
- Choosy - OS X utility ($12) to let you choose a browser when you click on a link.
- Ruby Versions - SSH access to a bunch of new and archived flavors of Ruby.
Double Shot #495
Time to get back on the daily sales and marketing wagon. Contract, where are you?
- Build Guild - Spreading social/technical gathering of web folks. I'd be tempted to start an Evansville/Newburgh chapter if I actually knew any other web folks around here.
- wikicloth - Mediawiki markup for Ruby.
- flickr_fu - I may need a flickr interface in Ruby soon. This one looks promising.
subscribe via RSS