Linked from Penny Arcade – PA Day 2009

Obsidian Portal, Promotion, Site Admin 4 Comments »

On January 23, Gabe over at Penny Arcade gave a fairly glowing review of Obsidian Portal. It was short and simple, but basically said “They get it” when it comes to managing a D&D campaign. Minutes later, the PA masses started streaming in, and thus began the craziest couple of hours in Obsidian Portal’s history, and what I will forever call PA Day.


Beware the Cave of Tits!

The Epic Tail

Our traffic spiked by at least 1000% pretty much immediately. Page load times skyrocketed from a second or so into nearly a minute range. To compound the issue, I was at work plugging away on a hard deadline of “right now!” I couldn’t just ditch and go work on Obsidian Portal, so I watched helplessly as we were wanged.

Luckily, Ryan was a little more flexible than me, and he got to work. Logging into our slicehost panel, he immediately started spinning up a slice with 2GB of memory. All the while he was giving me updates via IM. It was like something out of a BSG episode, with the heroes spinning up the FTL drive while the Cylons are swarming them. (Note: We don’t consider the Penny Arcade users to be Cylons, although they might like that.)

Ryan: It’s at 30%

Ryan: 60%

Ryan: 90% almost done

Ryan: 100% – New slice is ready. It’s syncing and doing the switch
Ryan: come on…come on…
Ryan: We’re up!

All the while, I was terrified that something would go wrong in the switchover causing both the original and the new slice to be inoperable. Further, what if there was a problem with the DNS, causing requests to go to the old slice instead of the new one? I thought I was going to throw up, I was so nervous.

But within only minutes our new slice was up and running and doing a much better at handling the influx of traffic. Still, just to be sure, Ryan went in and started tweaking Apache / Passenger settings to make sure that everything was in tip-top shape. As we all know, Apache is pretty damned complex and it’s pretty hard to get the settings just right for your particular instance, especially on the fly. Things were running much better, so I was finally able to start relaxing.

The Fallout

Obsidian Portal had a massive spike in both visitors and signups. Our overall traffic was up 1,000% from the previous day, but even better, thanks to Gabe’s endorsement, the Penny Arcaders were signing up at a rate twice as high as regular visitors. Compare that to your average digging, reddit, or slashdotting, where visitors browse through and possibly leave a hate-filled comment, then move on.

By the time the dust settled on Monday afternoon when Penny Arcade posted a new story on their homepage, we had received thousands of new signups and hundreds of new campaigns. All in all, it was a fantastic weekend.

Visits were way up, but even better…
Pageviews stayed high even as visits declined. That means we hooked some of them!

Lessons Learned

Success or Failure?


Campaign updates were streaming in.

When the first wave hit us and our server started collapsing, it seemed as though we had failed. Here were thousands of people trying to get to our site, and they just plain couldn’t. Ryan especially seemed very frustrated.

However, when I thought about it later, I realized that it was a success, even if the site would have crashed and burned. Why? Simply because thousands of people were trying to get to our site. People were eagerly attempting to connect to our server and in the meantime were spreading the word about our site through the blogosphere, twitter, and others, letting all their friends know how the guys at Penny Arcade thought Obsidian Portal was so awesome. They also found resources in other locations such as previous reviews, Obsidian Portal’s Twitter account, Obsidian Portal’s Facebook Page, and even Michael Harrison’s Viemo Video World Building with Obsidian Portal.

The lesson? Maybe you scale, maybe you don’t, but at least you proved your idea. It’s a lot easier to take a popular site and make it faster than it is to take a screaming fast site and make it popular. The technology issues are by far simpler than the social ones.

Break out the credit card immediately

The very first thing Ryan did was to spin up a bigger slice, and that had by far the biggest impact on the number of requests we could serve. We could have tweaked MySQL settings, adjusted Apache processes, or experimented with exotic caching. Maybe it would have helped, maybe not. Optimization is a tricky business. When you’re at the point where your server is on its knees, you don’t have time to figure everything out, so spend money instead of time. Call your host and say “Gimme the biggest one you got!” You can always downgrade later.

Make basic optimizations ahead of time

Go ahead and spend a couple hours doing basic optimizations. For example, on Obsidian Portal, we had already applied some aggressive caching to the home page prior to PA Day. It took Ryan a couple hours to figure out. That’s a couple hours we didn’t have on PA Day, so we’re glad we spent them up front. Lesson? Don’t go nuts and try to optimize everything, but go ahead and do the basics. Do it now! Don’t wait!

Always have two sysadmins

I’m glad I have a day job (and a paycheck!), but that means I’m not always available to handle issues with the site. On PA Day, I was in crunch time at work and therefore pretty much helpless for Obsidian Portal. Luckily, there are two of us who can essentially do everything. That way, there’s a much better chance that if something happens, one of us can get to it and fix it before it causes too much trouble. It’s important to have failover backups for people as well as hardware, and someone to double check your ideas before implementing them in a hurry.

Yay Slicehost

slicehost
Getting bigger iron was our fastest, safest, and best course of action. Slicehost made it easy. We were able to spin up a new identical slice with double the RAM and CPU in only a few minutes. Essentially, Ryan flipped a switch, waited 15 minutes, and we were on a beefed up server. No service call, no email, just raw speed. Perhaps other hosts offer this solution, I don’t know. What I do know is that Slicehost has always preformed exceptionally, and we thank them for that.

Yay Passenger

phusion-passenger
When Ryan wanted to move from Mongrel to Passenger, I was a little skeptical. I’m always hesitant to “fix” that which isn’t broke. Seems a little like running in place to me.

However, Passenger made scaling a snap, at least as far as server management went. No editing the mongrel cluster. No managing and restarting via God or Monit. Just leave Apache running and it will do its thing when the requests start rolling in. It’s just one less thing to worry about.

Going forward

Things have calmed down a bit now, and we’re back to the sure and steady growth that we’ve been seeing all along. Our new Penny Arcade fans have been successfully hooked and are steadily churning out new storylines, characters, and campaigns.

On our end, we’ll keep working on the site, adding features, fixing bugs, and improving server performance to be better prepared for more days like PA Day. The continual good feedback we get keeps us energized and hopeful that it will continue to grow. We may not be rich (yet), but we’re creating something that people love, and that feels great.

And one last thing. It’s a site written in Ruby on Rails and we made it scale!

Rails, Textile, and javascript WYSIWYG roundup

Plugins, Projects, Ruby on Rails 3 Comments »

If you allow rich text from your users in a Rails app, then you’re probably familiar with Textile. Either that or you’ve chosen the dark side, aka. Markdown. If that’s the case, I hate everything you stand for and I’ll bet you put your curly braces on the wrong line!

Assuming you’re one of The Chosen who has selected Textile as your input syntax of choice, you’ve probably got plenty of users who are turned off by the syntax. It may be easy for your average web developer to pick up yet another new syntax, but there are lots of people on the web who have never clicked the edit tab on Wikipedia, or think that links are specified with [URL=http://bbcode.com].

For these people, some sort of help is necessary. Quick tip sidebars, tutorials, and help pages only go so far. To make it truly useful you’ll probably have to dip into your Javascript bag of tricks. Luckily for you, a few others have already blazed that trail and created a handful of Textile utilities.


Textile Editor Helper (TEH)

NOTE: We’ve forked the Textile Editor Helper plugin to have more features and to conform to Rails 2.1 conventions. Our fork is available on github here:
http://github.com/felttippin/textile-editor-helper/tree/master

Textile Editor

The Textile Editor Helper is a very simple toolbar that sits at the top of your textareas, much like the Wikipedia toolbar. It provides many of the most basic Textile options, like bold and italics, plus some text alignment. Unfortunately, it doesn’t include linking and image includes, which are really easy to do with Textile.

Supposedly, you can add your own buttons, but I haven’t confirmed this. Plus, I think the whole plugin is based around the idea of prefixes/suffixes for text (like * for strong, or _ for em), so anything that requires more than that might not be possible. So, TEH is a good solution if all you need is some basic formatting help.

Live Textile Preview


The Live Textile Preview (aka SuperTextile) is simply a Javascript implementation of the Textile parser. So, you can convert Textile to HTML on the client side. This allows users to experiment with the syntax and quickly see what the changes will look like.

Unfortunately, from my cursory testing, it only implements most of the Textile syntax. Basic text changes, images, and links are covered. However, advanced text alignment and CSS styling elements seem to be beyond its capabilities. So, it’s not perfect. Still, if you only need the basics, SuperTextile can make life bearable for your users.

Sanskrit WYSIWYG editor

Sanskrit

Sanskrit is a true WYSIWYG editor, and the only one I’ve seen for Textile. However, it only does the absolute basics, so I can’t recommend it. Plus, I don’t think it’s a great idea to hide the raw Textile from your users. I’m a fan of the Wikipedia / Mediawiki way of things, where you provide some editing help, but your users are always looking at the raw text. Eventually, they’ll get the hang of things and won’t need the crutch of the editor buttons anymore.

markItUp!

markItUp! could be the most promising of all the solutions. A general purpose syntax parser written on top of jQuery, markItUp! can translate any syntax into HTML, provided you write the correct parser. Further, someone has already gone through the trouble and created a Textile parser!

I haven’t installed or tested markItUp!, but I was very impressed after playing around with the Textile demo. It seemed capable of most of the Textile syntax (including links and images), and even included a handy-dandy preview feature (you must render on the server side and return the HTML, I believe). So, it includes the best of all worlds: users work on raw Textile, but can get a live preview at the click of a button.

Update I finally got a chance to play with markItUp and it is hands down the best editor out of the bunch. Unless you need a true wysiwyg (in which case Sanskrit is the only one, AFAIK), then skip all the others and go straight to markItUp.

More?

Well, that’s all the Textile help I’ve found so far. Each one has its plusses and minuses, but any of them is probably better than a bare textarea with little or no help.

If I’ve left anything out, please let me know and I’ll add it to the list. With a little help, we can put together a comprehensive list of all the Textile tools available for Rails programmers.

Boosh! My first Rails core contribution gets accepted!

Ruby on Rails 1 Comment »

I submitted my first Rails core contribution a while back, and I just happened to check in and see that it was accepted!

Amazon EC2 first thoughts

Obsidian Portal, Ruby on Rails 1 Comment »

I’ve had my first brush with EC2 today, and I’m thoroughly confused and exhausted. It definitely has a much steeper learning curve than the other Web Services. However, since you’re dealing with booting and configuring fully functional virtual machines, I guess that’s to be expected.

Still, I managed to spawn an instance, set all the necessary permissions, and then connect to it via ssh. Not exactly something to brag about, but it is a milestone. I consider it $0.20 well spent. :) (I had to terminate and re-run the instance because I didn’t store the key-pair RSA key the first time.)

The goal

For Obsidian Portal, the map processing and tiling is very CPU and RAM intensive. If run on our Slicehost VPS, it totally bogs down the whole system, making the main website completely unresponsive.

So, we’ve offloaded the processing to a machine in Ryan’s attic. Although it’s worked so far, it’s not exactly a professional solution. Plus, Ryan’s getting ready to move and his machine will be off for at least a week. That means we need a new place to run our stuff. Since I’ve been meaning to dive into EC2 for a while now, this seems like the perfect opportunity to put in place a permanent and professional solution.

The plan

Whenever we need to tile a map, I plan to spin up an EC2 instance and run the tiler. I’ll keep the instance up for the rest of the hour, in case more maps come in. When the hour runs out, if there are no more maps to process, then we’ll spin down the instance. Computing power on demand…nice!

grempe-amazon-ec2

If you’re a Ruby hacker, skip the EC2 toolset altogether. Just go get the grempe-amazon-ec2 gem and run all your EC2 requests through an irb shell. This allows for opening up the EC2 developer reference and learning the API commands straight from the docs, rather than having to learn the EC2 toolset. You’re probably going to have to spawn/terminate instances dynamically at some point, so you may as well just learn how right from the start.

Besides, the EC2 toolset route involves setting up a JVM, setting JAVA_HOME, and all that Java mumbo-jumbo that always takes way longer than it should. Save yourself a headache and go straight to the source.

ec2onrails

I’m not looking to run a full Rails server (yet), but we do want to run some rake tasks. Rather than hand build an image, I’ve decided to start with the ec2onrails image and see if that gets me most of the way there.

The main downside is that this image will need to install RMagick, ImageMagick, and possibly other gems and packages each time it spins up. ec2onrails has built-in support for this, but it means that the map processing can’t start for several minutes after the image boots up, meaning our users have to wait to see their maps. For now, it should be acceptable, but it’s something to improve on.

Next Steps

I’ve had enough for today, but there’s still a ways to go. I need to complete the following:

  1. Setup the cron job on our VPS to spawn the EC2 instance whenever a map needs processing (and there’s not already an instance running)
  2. Setup the script (rake task?) for the EC2 image that will do the processing. It may as well just run forever. Maybe it can be responsible for terminating the image? Hmm…that sounds dangerous. If it should crash out, then the instance will keep running and billing us!
  3. Surely there’s more…

Oh, and one other next step: I’d better go terminate the instance I left running! ;)

My first Rails core contribution!

Ruby on Rails 2 Comments »

I just submitted my first Rails core patch! It was only a small issue dealing with a fairly unusual case (MySQL SSL connections), but heck, every patch counts, right? That’s how open source works.

It hasn’t been included yet, so I’ve got my fingers crossed…Wish me luck!

Hacking the Ultrasphinx plugin to work with paginating_find

Plugins, Ruby on Rails No Comments »

If you’ve been following our blog you may have noticed that we’re using Solr and ActsAsSolr plugin for our searching.

Getting started with acts_as_solr
acts_as_solr for development and production in one Tomcat instance
Optimizing Solr and Rails – Index in the background

Unfortunately being Java, Solr is a bit of a memory hog. We’ve attempted all sorts of optimizations, but we’re going to take a leap and switch to Sphinx. Sphinx is a free open-source SQL full-text search engine.

First step is to get Sphinx itself installed. For that have a look at Rob’s post:
http://www.notch8.com/articles/2007/10/15/sphinx-and-ultrasphinx-and-eye-on-search

Ultrasphinx works pretty much out of the box with will_paginate; however, a lot of our work is currently compatible with paginating_find. So to keep rails memory footprint down by using one plugin we’re sticking with paginating_find. Unfortunately Ultrasphinx doesn’t work out of the box with paginating_find, so time for a little hacking…

Install paginating_find plugin:

piston import http://svn.cardboardrocket.com/paginating_find/paginating_find vendor/plugins/paginating_find

More information on paginating_find

Install ultrasphinx plugin:

piston import http://fauna.rubyforge.org/svn/ultrasphinx/trunk/ vendor/plugins/ultrasphinx

More information on Ultrasphinx

Now for hacking Ultrasphinx plugin to work with Paginating Find plugin. Piston is great for managing plugins; however, it can easily get confused if you’ve hacked a plugin directly. The solution: use a method called “Evil Twin” as mentioned on the Err the Blog: Evil Twin Plugin

Create a directory for the hack:

mkdir vendor/plugins/ultrasphinx_hacks
touch vendor/plugins/ultrasphinx_hacks/init.rb

Now edit the vendor/plugins/ultrasphinx_hacks/init.rb file with the hacks for paginating_find:

# Hack to allow Ultrasphinx to work with pagination_find
Ultrasphinx::Search.module_eval do
def first_page
1
end

def last_page
self.page_count
end

def previous_page?
previous_page ? true : false
end

def next_page?
next_page ? true : false
end
end

Now for adding a method to your controller for the search:

app/controllers/posts_controller.rb

def search
@query = h(params[:query])
begin
@posts = Ultrasphinx::Search.new(:query => @query,
:class_names => ‘Post’,
:page => params[:page] || 1, :per_page => 20)
@ posts.run
rescue RuntimeError
flash[:warning] = ‘Search is currently disabled. Please try again in a few hours.’
rescue NoMethodError
flash[:notice] = ‘No records found for this search’
end
render :action => ‘list’
end

app/views/posts/list.html.erb

    < % @posts.each do |cog| %>

  • < %= posts.name %>
  • < % end %>

< %= paginating_links(@posts) %>

Paginating End Result

Bonus : will_paginate styled links

Unfortunately paginating_find doesn’t automatically have the “style” that will_paginate automatically comes with. So to fix that just add a little css for the style and a partial for the pervious and next buttons.

.pagination{
padding: 2px;
}
.pagination a, .pagination a:visited{
padding: 0 5px;
border: 1px solid #9aafe5;
text-decoration: none;
color: #2e6ab1;
}

.pagination a:hover, .pagination a:active{
border: 1px solid #2b66a5;
color: #000;
}

.pagination .currentpage{
font-weight: bold;
padding: 0 5px;
border: 1px solid navy;
background-color: #2e6ab1;
color: #FFF;
}

.pagination .disablepage{
padding: 0 5px;
border: 1px solid #929292;
color: #929292;
display: inline;
}

And now for the partial:

app/views/shared/_paginate.html.erb

< % if (collection.is_a?(PagingEnumerator) || collection.is_a?(Ultrasphinx::Search)) && (collection.page_count != collection.first_page) -%>

< % end -%>

So in your code replace the code paginating_links call with a render partial:

# OLD VERSION
< %= paginating_links(@posts) %>
# NEW VERSION
< %= render :partial => ‘shared/paginate’, :locals => {:collection => @posts} %>

Styled Paginating End Result

Resources:
ErrTheBlog: Evil Twin Plugin
Will Paginate Plugin
Paginating Find Plugin
Ultrasphinx
Sphinx

Installing GrowlNotify and Autotest for BDD use with Rspec on Leopard

Ruby on Rails 20 Comments »

I’m a big fan of Behavior Driven Development (BDD). It really illustrates how one little change in your code can have significant impact on the rest of you application, which you would never be able to catch without testing. Not to to mention the benefit of being able to write code and make sure it works even if you don’t have production data available.

So, upon completing a clean upgrade to Leopard I noticed that after installing Growl and growlnotify, that growlnotify would not work even through Growl itself was working.

1) First let’s set up the .autotest file. For this you’ll need the gems rspec (1.1.3), ZenTest (3.9.1), and redgreen since ZenTest change how it handled exceptions in 3.9.

sudo gem install rspec
sudo gem install ZenTest
sudo gem install redgreen

Now open up your ~/.autotest file in Textmate

mate ~/.autotest

Paste in the following code. Notice the exceptions at the bottom of the file that really helps speed up autotests as well as keeps your cpu usage low. My Macbook would get really hot really fast prior to using this execptions.

require ‘autotest/redgreen’

module Autotest::Growl
def self.growl title, msg, img, pri=0, stick=”"
system “growlnotify -n autotest –image #{img} -p #{pri} -m #{ msg.inspect} #{title} #{stick}”
end

Autotest.add_hook :ran_command do |autotest|
filtered = autotest.results.grep(/\d+\s.*examples?/)
output = filtered.empty? ? ” : filtered.last.slice(/(\d+)\s.*examples?,\s(\d+)\s.*failures?(?:,\s(\d+)\s.*pending)?/)
if output =~ /[1-9]\sfailures?/
growl “Test Results”, “#{output}”, “~/Library/autotest/rails_fail.png”
elsif output =~ /pending/
growl “Test Results”, “#{output}”, “~/Library/autotest/rails_pending.png”
else
growl “Test Results”, “#{output}”, “~/Library/autotest/rails_ok.png”
end
end

end

Autotest.add_hook :initialize do |at|
%w{.svn .hg .git vendor}.each {|exception| at.add_exception(exception)}
end

Next, you’ll want to download the Pass, Fail, and Pending images below and place them in ~/Library/autotest:

rails_ok.png rails_pending.png rails_fail.png

First, the prerequisite to growlnotify is Growl. You can download it from http://growl.info/. It’s a graphical installer, so you shouldn’t have an issues.

Once you’ve installed Growl, pop open the terminal and enter the following commands.

cd /Volumes/Growl 1.1.2/Extras/growlnotify
sudo sh install.sh

Give it a test run:

growlnotify -m “Testing growlnotify” Test

So if that doesn’t work, it’s probably because of an issue with the default permissions and Mac OS X 10.5 Leopard. Here’s what my permssions were. (I have no idea why the @ symbol is there)

cd /usr/local/bin
ls -l
-rwxr-xr-x@ 1 ryan 501 130288 Jan 22 17:38 growlnotify

To fix the permissions, I ran the following:

sudo chown root:admin growlnotify

Resulting in the following permssions:

cd /usr/local/bin
ls -l
-rwxr-xr-x@ 1 root admin 130288 Jan 22 17:38 growlnotify

Give it a test run again:

growlnotify -m “Testing growlnotify” Test

Now you can change directories to your rails app and run autotest and growlnotify should be working now..

cd ~/myrailsapp
autotest

Growlnotify Green

Growlnofity Red

References:
http://blog.codefront.net/2007/04/01/get-your-testing-results-via-growl-notifications/
http://www.danielfischer.com/2007/05/14/ruby-on-rails-bdd-with-autotest-growl-rspec/
http://railsontherun.com/2008/1/30/misc-tips-and-tricks/

Optimizing Solr and Rails – Index in the background

Plugins, Ruby on Rails 11 Comments »

Update: 2008-02-21 We’re looking into using ActiveMessaging and Amazon SQS to help with the workflow for background processing. Stay tuned for an updated post.

With before_save and after_save filters being so easy to use, it’s tempting to add more and more pre and post-processing to saving an ActiveRecord model. For Obsidian Portal, we update permissions, set timestamps of associated objects, and do all sorts of stuff. Unfortunately, all this extra work takes time, and can significantly slow down your application. The more work you do on the main execution thread, the more time Mongrel is tied up doing stuff unrelated to servicing requests. If something goes wrong in any of the filters, Rails will rollback the database transaction, and *poof* it’s all gone!

A while back, we started seeing ‘rbuf_fill’ timeout errors in the server logs. From what we could see, calls to acts_as_solr indexing were timing out, interrupting the save. For us, this was really bad. People would spend lots of time painstakingly crafting their perfect blog posting or wiki page, only to have it evaporate into nothing. All they saw was our default “Internal Server Error” page. Sure, it looks nice, but no one wants to see that ;)

Tracing the timeout back to Solr was not hard, and the solution was clear: take the indexing out of the main execution thread and move it to a background process. Luckily, acts_as_solr made this a fairly easy refactoring process. Here’s what we did:

Add an :if clause to your acts_as_solr macro call

acts_as_solr supports an :if clause that will be used to determine whether or not the record will be indexed when save is called. We want this to always evaluate to false, except when we explicitly set it to true during off-line processing. Below is an example from one of our models:

acts_as_solr :fields => [:name, :body, :post_title, :post_tagline, :slug],
:if => :solr_index?

def solr_index?
@solr_index
end
attr_writer :solr_index

Use rake/cron to do the indexing in the background.

Now that indexing does not happen on save, we need to make sure it happens at some point. Our solution was to move it to a rake task that gets executed by a periodic cron job. Rake + cron has worked well for us in the past, so we’ll stick with it.

The task itself is very simple. Find all the objects that have been updated since the last indexing, and push them to Solr.

Below is the rake task that I wrote. If I were more clever, I would probably come up with a neat trick for automatically finding all the models that support Solr indexing. Now that I’m an official committer on acts_as_solr, maybe I’ll try to figure something out and get it into the trunk. Still…I’m lazy :)

namespace :solr do
namespace :index do
desc “Indexes campaigns”
task :campaigns => :environment do
index_class(Campaign)
end

desc “Indexes wiki pages”
task :wiki_pages => :environment do
index_class(WikiPage)
end

desc “Indexes game contents”
task :game_contents => :environment do
index_class(GameContent)
end

desc “Indexes users”
task :users => :environment do
index_class(User)
end

desc “Indexes everything that we’re storing in solr”
task :all => [:campaigns, :wiki_pages, :game_contents, :users]

def index_class(klass)
# If REBUILD is set to “true” then we rebuild the entire index
rebuild = ENV["REBUILD"] ? ENV["REBUILD"] == “true” : false

interval = rebuild ? 100.years : 30.minutes

objects = klass.find(:all,
:conditions => ["updated_at > ?", Time.now - interval],
:page => {:size => 20, :auto => true}
)

objects.each do |o|
puts(“Indexing #{klass.to_s}: #{o.id}”)
o.solr_index = true
o.solr_save
end
klass.solr_optimize

end
end
end

Set up a cron job to run this every thirty minutes or so. For most sites, a half hour will be a good balance between keeping the load down and making sure the searching is fairly up to date.

By moving the indexing off the main thread, we’ve noticed a significant reduction in the number of Solr related exceptions. That means our users have seen a significant reduction in the number of “Sorry, we lost all your data” errors, and that is exactly what we were hoping for.

References

New SD.rb Talks Posted: Simple Sidebar Plugin & Ajax CSS Star Rating with ActsAsRateable

Plugins, Ruby on Rails No Comments »

My podcasts / vidcasts at SD Ruby have been posted to the podcast section.

Simple Sidebar Plugin

How to use Simple Sidebar plugin to DRY up sidebar content in applications.

SD.rb Vidcast - Simple Sidebar Plugin

Related Blog Posts:

http://blog.aisleten.com/2007/06/03/simplesidebar-if-you-have-sidebars-you-need-this-plugin/

Ajax CSS Star Rating with ActsAsRateable

How to build an Ajax-powered, CSS star rater using the ActsAsRateable plugin and Komodo Media’s CSS Star Rating Redux technique.

SD.rb Vidcast - Ajax CSS Star Rating

Related Blog Posts:

http://blog.aisleten.com/2007/05/03/ajax-css-star-rating-with-acts_as_rateable/
http://blog.aisleten.com/2007/05/17/find-the-top-5-highest-rated-objects-with-acts_as_rateable/

At this month’s meeting we’re going to be having our first Rails Roundtable so come and check it out.
SD.rb December Meeting Schedule

Atlanta Ruby Users Group

Ruby on Rails No Comments »

The Atlanta Ruby Users Group (ATLRUG) recently moved their meetings to a much friendlier location for me. Rather than heading up into the forbidden north of Atlanta, it is now being held in the convenient location of Tech Square in Midtown. Of course this probably means nothing to anyone reading this from outside Atlanta.

In any case, it was a really great group, and they were very welcoming to new people, of which there were very many. Following the free pizza and pre-meeting chit-chat, we saw two presentations.

Metaprogramming

First up was Stephen Touset with a talk on metaprogramming. This is what is going on behind the scenes with all the method_missing stuff. Probably the most well known example would be the dynamic finders (ie. “find_by_email_and_username”). Stephen delved deep into metaclasses, and it was fairly confusing. I’ve dealt with class_eval and such before, but mainly from a “copy someone else’s stuff and modify to suit” sort of way. As I said during the meetup, “It’s possible to do metaprogramming without knowing what you’re doing.”

Nginx

Mark Percival followed Stephen with a presentation on Nginx, a fast little web server. I’ve always been a fan of Apache, but mainly because I felt safe with it. Even though it was a pain to configure, I knew that if I ever had to ask “How do I do X on the web?” then the answer would be in Apache language.

However, it never occurred to me that it might be overkill. As Mark explained, if all your Apache server is doing is proxying to mongrel, then it’s a big hammer for a tiny problem. The memory footprint is fairly high, and the configuration is a pain. Face it, Apache is not very friendly.

Mark claimed that Nginx was friendlier. To be fair, the config file was shorter. However, it still looked fairly arcane to me. I guess easy is in the eyes of the beholder.

Still, the memory issues are something I can’t ignore. Obsidian Portal runs on a VPS from Rimuhosting, so memory is a scarce resource. If I can reclaim enough memory to run another mongrel instance, that would be quite a coup. However, the real offender on my VPS is Tomcat. What!?! Tomcat!?! Well, I needed something to run Solr, and Tomcat is the only servlet container I’m familiar with. So, even though it’s a memory hog, it’ll have to stay for now.

Overall thoughts

All in all, the meetup was great. As I said, everyone was very nice, and all seemed fairly down to earth. There were no pissing contests over who was the better hacker, and newbie questions were answered honestly and humbly. I can’t wait until next month’s meeting. Maybe I’ll even try to scrape something together to present.

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in