I learned something interesting the other day about using sessions with multiple rails apps: be careful with storing models in sessions. Or, to put it another way, don't store models in sessions. Well, you could, but you'd have to make sure that the model was included in each of your apps. This is, of course, entirely possible, but we're not doing it currently, and thus we get this:
session[:user] = User.find(15)
.User
model.session[:user_id] = 15
, then create a local instance variable of the model. Or, if there are a few common things that'll be used, create things like session[:user_firstname]
or session[:user_email]
. This should ensure less random carnage due to model mismatches.
This is only going to be of interest to people who are both programmers and musicians. I only barely fall into the latter category, but I did come across a great open source project today that perfectly solved a problem I had.
For an upcoming performance (it'll be the third time I've played in public), I was handed some photocopied sheet music. The pieces had been copied multiple times, and were pretty much unreadable. Now, I have enough to worry about when I'm playing without trying to figure out what the notes are, so something needed to be done.
I'd downloaded the free version of Finale some time ago when I hit a similar problem with another piece of music. At first it was fun to place the notes on the screen, but I soon hit limitations. It was impossible to make the computer version look anything like what I had in front of me because it automatically decided how to space out the bars and when to do line breaks (and it didn't look good doing it, either). This is an obvious problem when playing with other people and they say "start on line 4" or something like that, and your line 4 isn't their line 4. I pretty quickly gave up on Finale, and based on the experience, I wasn't too keen on upgrading to their higher-end software. And some of the other commercial music notation packages looked really pricey.
But I ran across this cool little app/project called LilyPond. Basically, you write the music in a text editor, and then use LilyPond as a rendering engine to produce a PDF (it'll also spit out a midi file, which is fun, too). If you have any programming experience, you'll find the notation markup to be quite easy to pick up. Shoot, if you've ever done basic HTML, you'll probably get the idea. And, much to my delight, the system is very customizable. In other words, I can make it do what I want it to do. As an added bonus, the output looks great. I couldn't be happier with it!
Last night I heard a science lecture. In an NBA arena. An odd combination, for sure, but it makes more sense when you know it was Al Gore doing his global warming thing. I'll skip the political points, and say a few words about the presentation style. We weren't exactly close to the screen...at least the length of a basketball court, and probably farther, off to the side, and elevated (aka the cheap seats). Yet, Gore's visuals worked at even a long distance. We couldn't always see the details, but the message came through loud and clear. Very nicely done. Anyone who ever speaks in public could learn something by watching this presentation.
For more info on Gore's presentation, check out these two great posts on Presentation Zen: Al Gore: another presenter extraordinaire? and Duarte Design helps Al Gore "go visual"
I'm looking forward to day two of IDEA2006. After an enjoyable day one, I'm thinking of IDEA as the poor man's TED, in the sense that it brings interesting people together to share what they're doing (with an information bent), and yet doesn't cost thousands of dollars.
It looks like there are a few session summaries over on the conference blog. Favorites so far include Linda Stone and Jake Barton. There are rumors of podcasts...stay tuned.
(BTW, I wrote about my motivation for attending IDEA in an earlier post.)
Rails relies on convention, and one of the conventions is that you'll be connecting to just a single database. This, of course, makes plenty of sense in most situations. But, some of you may be facing a situation where you'd want to connect to multiple databases. The reasons aren't always clear, but they can usually be summed up in the word "legacy".
Rails doesn't make it easy to handle multiple databases. As far as I know, the way to handle this is to add the following bit of code to each model that is to be hooked to the second database:
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:socket => "/tmp/mysql.sock",
:username => "my_username",
:password => "my_password",
:database => "my_second_database"
)
This is all fine and good, if considerably more verbose than the standard configuration. And not too onerous if you're just talking about a model or two. But, sharp readers may notice that we're hardcoding in things like passwords and datasources. And, if you're like me and have separate databases for development, testing, and production, you might find yourself in a bit of a quandary. You really don't want to be hardcoding in "MyDatabase_Dev", and you really don't want to have to remember to change that to "MyDatabase_Production" when making your app live. Trust me. I learned the hard way.
But, Rails has a great feature that can help here: environments. Simply define a variable in config/environments/development.rb and config/environments/production.rb (and test.rb, assuming you want to run tests). Call it something along the lines of DATABASE_NAME, and assign it the name of the development DB in development.rb and the production database in production.rb Then, you can define things like:
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:socket => "/tmp/mysql.sock",
:username => "my_username",
:password => "my_password",
:database => DATABASE_NAME
)
That way, when you switch environments, the database will switch automatically. You can pull the same trick with usernames and passwords, too.
No, this isn't ideal, but it works *much* better than trying to remember to manually switch things!
I'm a big believer in the "Don't Repeat Yourself" (DRY) principle, as is the Rails team. One place this pops up is in our website's navigation. Like pretty much any site that grows beyond a few pages, we're including a navigation file into each page on the site. There isn't anything fancy going on here: we're just setting a few variables on each page (page name, section, subsection, and so on), then showing or hiding parts of the navigation "tree" accordingly.
There are (at least) two ways to do this: store the navigation information in the database or in a flat-file of some sort. I chose the latter method. Storing this info in a database can be expensive, in terms of the number of database calls required to generate each and every page. I don't think it is a great idea to build in a required 2-3 DB calls per hit, and a navigation caching system probably isn't worth the additional complication. So, we're storing the navigation "tree" in a series of nested PHP arrays and a bit of PHP code basically "walks" the tree, looking for matches to a given section or page name, producing the HTML navigation menu accordingly. It is fast and simple. The gotcha here is that this is *PHP* code. And now I want to use it for a Ruby on Rails app. I don't want to have to re-create the entire array in ruby, because maintaining two identical sets of source for the navigation would be, well, pretty stupid.
So, the solution was to write a bit of a PHP that will read the PHP array and convert it to ruby code. Then, I wrote a Rails helper to walk through the ruby version and generate the navigation menu in HTML. I set up a cron job to automatically run the translator from PHP to ruby, and the problem was solved! We're able to use the same source file (in PHP) to power both systems, and it doesn't require any extra thought on our part (thanks to the cron job).