Alex Iskold's really cool list of the Top 10 Concepts That Every Software Engineer Should Know has completely whetted my appetite. Add Flex and Open Social development to this list and that's like the next year of my life. Hell yea.
Just came across this awesome post that describes how to fix an annoying bug with autotest that causes it not to show up like half the time. I hated having to go back to the terminal whenever growl didn't popup; every time it was another half second of my life wasted. I must've wasted upwards of 3 minutes because of this bug. I could've killed like 3 level 11 Goretusks in that time (just started playing WoW - level 15 Human Lock, username merckens, keep an eye out for me - I'll be the guy dominating everyone). If you've noticed this problem with your autotest-growl interaction, read the post. Worked for me.
Rails has come a long way quickly, but one of the biggest problems with our favorite MVC framework is support for multiple databases.
Sure you can use self.table_name and/or establish_connection to force a model to point to a table in a different db, but try running a freaking test with fixtures for the offshoot models, and you'll see what I'm talking about.
Even more depressing is SQLite3's lack of cross-database query join support, making this statement impossible:
has_and_belongs_to_many :blocked_users, :class_name => 'User', :join_table => :blocked_users, :foreign_key => "user_id", :association_foreign_key => "blocked_user_id"
Here's the kicker: All of our apps are multi-database apps, so that means no more SQLite allowed for us, and I really loved it until now.
If I'm wrong, let me know. I'd love to go back to using SQLite for local development. Same for an easy way to load fixtures.
I love this: Reddit, Stumbleupon, Del.icio.us and Hacker News Algorithms Exposed!
Reddit's algorithm is probably my favorite, using logarithms to weight earlier votes more heavily. Although I do enjoy the StumbleUpon "safety variable" (which keeps it from being totally gamed). And the del.icio.us algorithm is kind of remarkable in its simplicity. As Danny says though, the "10,000 Pound Gorilla in the Room" is of course Digg's algorithm, which is stored in a single machine buried 5 miles below the surface of the Earth.
Opened up irb and had a little fun this morning:
%w(good morning dary).each {|w| system("say -v Victoria #{w}")}
Awww. Good morning to you too Victoria ![]()
I've recently been tearing through various video tutorials that are out there including the ones produced by the fine folks over at railscasts.com.
A recent favorite that I've watched and implemented on Fan Profiles is the one about Site Wide Announcements. This is something that is pretty essential to any growing online community. Sooner or later you're going to want to message all your users about something, whether it be scheduled maintenance, new features, or other bits of info that may be relevant to the community as a whole.
One of the many cool projects that we've been working on is a killer new game available on Facebook. It's call Fight for the Top and it's probably the best Facebook sports app evar.
Today we launched the announcement system and have more than doubled the number of Fight for the Top users we had prior to today in a short few hours. We haven't done any promo for the app up to this point and it hasn't been available for very long but it was nice to see that the announcement system had an immediate effect on its user base.
I made a few tweaks to fit the code that Ryan covers in his screencast to make it work within Fan Profiles but for the most part kept it pretty much the same. Another great thing about these screencasts is that many others from the community offer up their input and/or improvements in the comments section. In this episode there was some good stuff added to railsforum.com and geoff.evason.name that is worth a look. In particular, the Geoff Evanson tips included using a cookie to track wheather a message has been hidden instead of a session which I found to be handy.
I tried to use Ruby's built-in Active Record fixtures module to import an Excel-exported CSV file. No dice. Kept getting cryptic errors about improper formatting. Whoops. So then I installed this wicked cool gem named FasterCSV and piggy-backed off of this migration import script and everything went great. So for all those people with ancient (and kinda useless) Excel data files, now there's a relatively quick and painless way to import them into SQL dbs. Here are the steps I went through:
Install the gem:
sudo gem install fastercsv
Now I have several tables in my College Football spreadsheet and for this example I'll use the one with ratings data for College Football games. Each entry has a game_id, region_id (for the various regions where ratings data comes from, e.g., Atlanta and Austin), a rating, and a duration in quarter hours (since some games are only cut-ins, e.g., Georgia Tech-Georgia ends early and the Atlanta region picks up the last half hour of the Texas-Oklahoma game). So here's the script that imports my gross Excel spreadsheet into a useable SQL table - db-agnostic by the way (How do I love thee Rails? Let me count the ways.)
require 'fastercsv'
class LoadRatingsData < ActiveRecord::Migration
def self.up
FasterCSV.foreach("#{RAILS_ROOT}/db/migrate/fixtures/ratings.csv", :row_sep => "\r") do |row|
id,game_id, region_id, rating, duration = row
Rating.create(:id => id, :game_id => game_id, :region_id => region_id, :rating => rating, :duration => duration)
end
end
def self.down
end
end
And it's just that easy. Another cool thing, that I haven't done yet, is that you could take that one bulky Excel sheet that has way too much information in it, break it into useful models, and form actual relationships between the data. What a novel idea!
In Conclusion,
This rules!
I wrote a script tonight to curl several URLs, but sleep for 2 minutes in between each request. I piggybacked on a little script written by programmer John McCann from NYC. Here's what the code looks like:
#!/usr/bin/env ruby
RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + '/..')
require File.join(RAILS_ROOT, "config/environment")
puts "writing curl script..."
t1 = Time.now
foos = Foo.find_by_sql("select distinct bar from foos;")
curls = foos.map! {|foo| "curl 'https://some.api.com?data=%7Bfoobar%3A#{foo.bar}%7D&key=12345'\n"}
curl_script = curls.join("sleep 120\n")
File.open("curl.sh", "w") {|f| f <<>
t2 = Time.now
puts "curl script written in " + (t2 - t1).to_s + " seconds"
What's fun about this script is that it was a new challenge for me on a couple fronts. I learned about encoding curl requests (%7Bfoobar%3A#{foo.bar}%7D produces {foobar:[value_of_foo.bar]}). After clumsily grabbing all objects and filtering after the query, I refactored the SQL to just grab distinct values from the db. I learned that the "w" attribute of the File.open class method either creates a file or sets its byte count to 0 if it already exists. And finally I learned about the "sleep" function which takes an integer parameter representing the number of seconds to wait until the next line is executed - this was especially helpful in not hammering the service I was accessing.
So not a major script, but pretty fun and interesting nonetheless.
In Conclusion,
I heart curl.
Behavior-driven development (BDD) is a programming paradigm that emphasizes defining behavioral characteristics of your code before actually writing any code. An example is if I'm defining a calculator controller my calculator should return 2 when given the equation 1 + 1, should return an error when trying to do division by 0, etc. By clearly defining what your code should do before writing it, it makes it much easier to write solid, test-covered code upfront and makes it a cinch to debug as you go along because you're immediately alerted whenever new functionality accidentally breaks legacy portions of your codebase.
I've found BDD much more intuitive than TDD (test-driven development). The above video by Dave Astels, one of the original developers of rSpec, gives a nice overview of BDD vs. TDD and the pros of the former. Also touches on the benefits of using a dynamic language like Ruby.
In Conclusion,
Pretty neat...
When we launched Fan Profile just over a week ago, we knew there would be bugs, refactoring and tuning.
There always is.
Minus the bugs, I love this phase. The pressure to launch is gone, and my attention turns to making the product perfect. I mean, who doesn't like perfection?
This time, my pursuit took me and the entire team into huge pile of CRUD.
I had just finished reading the "Gospel of the Seven Actions" (new, show, index, edit, update, create, destroy), and just that easily, I became a born again CRUDian.
My plan was to go through all our controllers and simultaneously tune queries, move code to models and "CRUDify" manufactured actions such as "search, about, mail, send_group_invite" and more.
I figured I could do it incrementally and quickly, so there was no need for a branch -- I'd be done in a day, day and a half.
Whoooopsss.
Yeah, I'll branch in the future because this was no easy task.
Some actions just don't fit nicely into one of the seven. For example, what about an action that takes a comma separated list of positions and rearranges a user's favorite teams based on those parameters?
Well, I had called it "reorder," but delving into the Gospel, I found out that what I am in fact doing is updating an existing order, so we get:
map.resources :users as 'fans' do |users| users.resource :team_orders, :controller => :user_team_orders end
Notice it is resource not resources. This means that a team can have ONE order, so you can specify the update action without specifying an id, which is good because there is no "order" model anywhere that maps to a table.
In the case of groups, we actually split one controller into eight, but the task is winding down.
I'm fixing the tests and caching and then I'll QA, hopefully in time for a release Monday. Then Fan Profiles will be one giant piece of CRUD where all exposed actions will be "one of the seven" (cue the choir).
If I didn't have a financial accounting mid term on Sunday, I'd celebrate our walk into the CRUDdy light.