Skip navigation

NEED HELP?|

Active Product Development

8 Posts tagged with the ruby tag

HAML vs. ERB

Posted by JeremyGThomas Jun 5, 2012

Three of the products I run technology for are built in Ruby on Rails.  Two of those projects use HAML as the view templating language, while the third is in ERB.  In an informal effort to explore the pros and cons of each to determine if standardization across teams was necessary I ignited a religious war.  Some are passionately pro-HAML, while others are passionately pro-ERB.  Today, in order to be more objective about things, I held a meeting with all of the Ruby developers to compare the two.  Here's what we came up with:

 

haml-erb.JPG

And here's a translation (black - "pro", red - "con")

 

HAMLERB
Faster CodingClose to HTML
Close to CSS Syntax (+1)Generally Understood
Forced FormattingStandard (+1)
Scanability (+3)ERB is applicable to all view files (via extension)
Value given to Whitespace (+2)Overly Verbose
Value given to Whitespace (yes, someone argued this as a positive)HTML is Error Prone (i.e. missing closing tags)
Tendency to Over Use DivsCloser to what the Browser Sees
Less CodeCloser to other languages (+1)
Learning Curve (+1)
Ruby Conditional Statements cannot be Intermixed withing JS blocks
Not standard and likely won't be
Forces succint Views
Follows the spirit of Ruby (beautiful code)
Looks like Perl with Excessive Symbols
"Shells" out to other languages

 

Given this list, we had a healthy debate about the value of each templating language.  In the end we decided the differences between the two weren't great enough to refactor our code in the name of standardization.  But we did decide to use ERB as the default, namely because of its proximity to other languages (i.e. PHP) and the correlating low ramp up time when training new developers in Ruby on Rails (including HTML/CSS developers).  So, with any new project we initiate in Rails there has to be a good reason not to use ERB, and a discussion will ensue to make a decision about which is best for said project.

4,130 Views 0 Comments Permalink Tags: ruby, ruby_on_rails, erb, haml

Developer Week - Rails 101

Posted by JeremyGThomas Aug 25, 2011

Continuing our effort to share what we've covered during Developer Week, Rob Cameron (again) teaches us about the beauty of Ruby on Rails:

2,446 Views 0 Comments Permalink Tags: ruby, developer_week, ruby_on_rails

Developer Week - Ruby 101

Posted by JeremyGThomas Aug 24, 2011

We're in the midst of Developer Week here at Active - a mini conference for employees to share knowledge about technology. Rob Cameron gave a great presentation yesterday about Ruby, and I thought I'd share his slides below:

 

2,158 Views Permalink Tags: presentation, ruby, developer_week

https://github.com/images/error/angry_unicorn.png

The general internet discovered Unicorn after a blog post over at GitHub. I've been wanting to use it for a while now. Early this week we switched over Trainer 2 to this awesome web server.

 

The idea behind Unicorn is that instead of having a separate load balancer with all kinds of fancy rules to determine which workers are busy and which are available to do some work, you let the tried and true process management built into your OS do that work for you. Unicorn consists of a master process that spawns workers. The master monitors the workers and kills and restarts any that are behaving badly. When a request comes in the master hands it off to the operating system to determine which worker process has the resources available to work on it. The stack looks like this:

 

https://d3nwyuy0nl342s.cloudfront.net/img/a91702456cf39acf5548524593fb19c6d1a84c42/687474703a2f2f696d672e736b697463682e636f6d2f32303039313030392d6e686b787072726e7463346b39753178346b62653134783631742e706e67

You stil want to keep your web server (nginx in our case, or Apache) serving static content. You just let the server know where to pass all the other requests to. In nginx this looks something like:

 

upstream trainer2 {
  server unix:/tmp/unicorn.sock fail_timeout=0;
}
server {
  listen 80;
  server_name trainer.active.com;
  root /var/www/current/public;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_max_temp_file_size 0;

    # serve static content with a far-future expires header
    location ~ ^/(images|stylesheets|javascripts)/ {
      expires 10y;
    }

    # if the file exists (static stuff) serve it right away
    if (-f $request_filename) {
      break;
    }

    # otherwise pass it on to unicorn
    if (!-f $request_filename) {
      proxy_pass http://trainer2;
      break;
    }
  }
}

 

 

That's it for nginx. Now to start up Unicorn you need a config file (ours is in /config/unicorn.rb):

 

# Sample verbose configuration file for Unicorn (not Rack)
#
# This configuration file documents many features of Unicorn
# that may not be needed for some applications. See
# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
# for a much simpler configuration file.
#
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.

root = '/var/www/current'

worker_processes(ENV['RACK_ENV'] == 'production' ? 8 : 2)
working_directory root # available in 0.94.0+
listen "/tmp/unicorn.sock"
timeout 120

pid "#{root}/tmp/pids/unicorn.pid"

stderr_path "#{root}/log/unicorn.stderr.log"
stdout_path "#{root}/log/unicorn.stdout.log"

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

  old_pid = "#{root}/tmp/pids/unicorn.pid.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

 

 

Now we just start up Unicorn like so (from our application's root directory):

 

unicorn -E production -c config/unicorn.rb -D

 

And that's it! You should be able to hit your server and have Unicorn respond. The true magic starts when you want to do a deploy: you don't have to have any downtime because Unicorn will start up a new master while the old one continues to serve clients. Once the new master is up and running, the first worker it spawns will turn off the old master. Users never saw a delay and you were able to upgrade your app transparently. Using this technique you can upgrade Unicorn itself, or even Ruby with no downtime! To trigger this restart just send the USR2 signal to Unicorn. First, run a ps aux | grep unicorn to get the process list and send the signal to the existing master process:

 

ubuntu@qa:~$ ps aux | grep unicorn

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
ubuntu   23511  0.0  4.0  80216 71040 ?        Sl   May04   0:15 unicorn master -E qa -c config/unicorn.rb -D                                    
ubuntu   23641  0.0  5.0  99108 88576 ?        Sl   May04   0:51 unicorn worker[0] -E qa -c config/unicorn.rb -D                                 
ubuntu   23644  0.0  5.0  98004 87632 ?        Sl   May04   1:14 unicorn worker[1] -E qa -c config/unicorn.rb -D

ubuntu@qa:~$ kill -USR2 23511

 

After a few seconds (however long it takes for your Rails app to start) you'll begin serving your new code. Done!

1,654 Views 0 Comments Permalink Tags: trainer, ruby, rails, unicorn

ActiveRecord is great but it can be a little scary to think about using it without Rails. Here's a quick example of using it with Sinatra.

 

The first thing we'll want to do is get the ActiveRecord gem by itself (throughout this tutorial I'm assuming you're using Bundler to manage your gems):

 

gem 'activerecord', :require => 'active_record'

 

Next up, in the configure block of our Sinatra app, we'll set up the AR connection to our database:

 

ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'db/development.db')

 

Of course, if you want to stay flexible, you can move your database config into a YAML file (laid out the same as the Rails standard config/database.yml file) and pull the connection details from that:

 

db_config = YAML::load(File.open(File.join(File.dirname(__FILE__),'config','database.yml')))[Sinatra::Application.environment]
ActiveRecord::Base.establish_connection(db_config)

Now that AR is ready to go we can include our models. I like to move my models into separate files, similar to Rails's app/models, so I tell Sinatra to include every file in that directory:

 

Dir.glob('./app/models/*').each { |r| require r }

 

Believe it or not, that's really all you need to do to start using AR in your Sinatra application! The only missing link is database migrations. AR comes with a huge Rake file full of tasks like db:migrate, but unfortunately those rely on being inside the shell of Rails (they look for environment variables like RAILS_ENV and the base Rails object all over the place). Here's a very simple piece of code that will enable the standard db:migrate task:

 

require 'bundler'
Bundler.require


desc "Migrate the database through scripts in db/migrate."
task :migrate do
  ActiveRecord::Base.establish_connection(YAML.load(File.read(File.join('config','database.yml')))[ENV['ENV'] ? ENV['ENV'] : 'development'])
  ActiveRecord::Migrator.migrate("db/migrate/")
end

 

This assumes that your migration files are in db/migrate. When you want to migrate in an environment other than development just set the ENV variable:

 

rake db:migrate ENV=production

 

That's it! There are a couple of different database ORM libraries out there besides ActiveRecord (like Sequel and Datamapper) but AR is the most popular today and it's easy to use it in all of your web apps, whether they're Rails or not.

9,702 Views 0 Comments Permalink Tags: ruby, sinatra, rails, database, activerecord

Ruby on Rails comes with a bunch of great rake tasks to help you work with your application. One of them is rake stats which counts the lines of code in your controllers, models and tests. It's a pretty neat utility that we use all the time to make the Java developers jealous.

 

I've been working on a little Sinatra application and wanted to use the same functionality. The rake stats command used the CodeStatistics class from one of the core Rails packages called railties (that's "rail-ties" as in the wooden slats that hold up train tracks, not "rail-tees" like t-shirts about trains). Now, the good Ruby developer in me says to simply require 'railties/code_statistics' from in my Sinatra application. However, I also realize that my Sinatra application has nothing to do with Rails and never will. So I did the unthinkable: copy-paste. In this case I don't think it's that bad: code_statistics probably hasn't changed much since Rails 1.0 and it's not something that I care about keeping in sync with the master development branch of Rails. Don't sweat it.

 

I put code_statistics.rb in a new directory in my Sinatra app called vendor which is a Rails convention for code from third-parties. Normally I would just put this code into lib, but in this case rake stats includes the lines of code in any files in lib, and I didn't want to throw off my numbers. In my Rakefile I added a new task (also copied from the Rails default Rakefile with a couple modifications):


desc "Report code statistics" task :stats do   require './vendor/code_statistics'     STATS_DIRECTORIES = [     %w(Controllers        app/controllers),     %w(Helpers            app/helpers),     %w(Models             app/models),     %w(Libraries          lib/),     %w(Migrations         db/migrations),     %w(Views              app/views)   ].collect { |name, dir| [ name, "./#{dir}" ] }.select { |name, dir| File.directory?(dir) }   CodeStatistics.new(*STATS_DIRECTORIES).to_s end

 

The modifications in this case are the directories that should be scanned for code lines. By default Rails doesn't include your views as counting towards your totals, but I wanted them to. I also have lots of migrations and would like to know how those contribute as well.  If you have any directories in addition to these just add them to the STATS_DIRECTORIES constant. I also wanted to count the number of comments in my code. I'm a big proponent of commenting and I'd like to know what ratio of my code is used to tell my future self how everything works. You can get a copy of my code_statistics.rb file (with comment-counting mods) here: https://gist.github.com/823219

 

And that's it! Now just rake stats from the root of your Sinatra app and you'll see something like this:

 

+----------------------+-------+-------+----------+---------+---------+-----+-------+ | Name                 | Lines |   LOC | Comments | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+----------+---------+---------+-----+-------+ | Controllers          |    65 |    50 |        8 |       0 |       0 |   0 |     0 | | Helpers              |    41 |    32 |        0 |       0 |       7 |   0 |     2 | | Models               |    12 |    10 |        0 |       2 |       1 |   0 |     8 | | Libraries            |     8 |     6 |        1 |       2 |       1 |   0 |     4 | | Migrations           |    78 |    71 |        4 |       0 |       0 |   0 |     0 | | Views                |    45 |    39 |        0 |       0 |       0 |   0 |     0 | +----------------------+-------+-------+----------+---------+---------+-----+-------+ | Total                |   249 |   208 |       13 |       4 |       9 |   2 |    21 | +----------------------+-------+-------+----------+---------+---------+-----+-------+   Code LOC: 208     Test LOC: 0     Code to Test Ratio: 1:0.0

 

585 Views 0 Comments Permalink Tags: ruby, sinatra, rails, rake

I put together a presentation this past week about building small, fast websites with Ruby and Sinatra, and then deploying them on Heroku. I had less-technical users in mind with this presentation. If you're a hardcore developer you have no problem setting up a web server from scratch. This is geared more towards designers who can make beautiful sites but aren't used to making them dynamic or pushing them public to the world.

 

You can download the sample code used in the presentation from here:  http://empty-journey-91.heroku.com

 

1,786 Views 0 Comments Permalink Tags: development, leg, web, ruby, sinatra, heroku

Active Widgets

Posted by RobCameron.2.16b Mar 1, 2010

Hi, I'm Rob and I'm a Software Architect on the Light Engineering Group here at Active. LEG, as we call it, was modeled after the LED group at LinkedIn. LinkedIn was looking for a way to rapidly prototype new technologies and architectures with Ruby on Rails. Their first product was Bumper Sticker which at one point was the mostly highly trafficed Facebook application in existence! You can find many of the fruits of LEG's labor at http://labs.active.com

 

This morning we officially launched our new Active Widgets site at http://widgets.active.com This was a quick two week project to create an embeddable window into Active.com's thousands of registerable events. The idea being that the blog you write about running/cycling/baseball can show a list of upcoming marathons/track events/Little League games in your area. The widget is customizable as far as what activities it displays, where it displays them, whether or not the user can change those settings, as well as the size and color of the widget itself. Once your done just click a button and you're given a couple of simple Javascript tags to drop onto your site wherever you want the widget to appear. And since the widget is written out onto your page like any other HTML, you can further customize it using your own CSS.

 

widget.png

 

The Technical Stuff

This customization site (known as The Configurator) is a Sinatra application written in Ruby. There is no database—the data store is a single YAML file which defines a widget and what about it is customizable. The widget itself is written in Javascript and after minification with the YUI Compressor, the whole thing is 14K (for comparison, the Google homepage is 47K).

 

Since we planned on having the widget be embeddable on any website we couldn't use Ajax to pull in the event listings. Ajax is subject to strict cross-domain security policies set by your browser—you can only access servers in the same domain that the page itself was served from. This is quite a problem since search results are coming from http://search.active.com  The workaround for this issue is to make server calls with <script> tags and then wrap the resulting code in a function call known as a callback. When the <script> tag is added to the page the browser immediately executes it as valid Javascript. Since this Javascript contains a function call (the callback) it looks a function you've already defined with the same name and calls it, passing in the returned data.

 

The server itself is an Amazon EC2 instance running in their cloud infrastructure. This allows us to quickly react to any scaling needs by simply spinning up a new instance of the same server and deploying the code to it. Nearly half our division's products are now running on EC2 and we're moving more there every day. We've found it be an fast, secure and cost effective way to get our applications live.

 

Stay tuned for more exciting projects from the LEG team!

1,901 Views 0 Comments Permalink Tags: events, widgets, leg, cloud_computing, amazon, ec2, labs, ruby, sinatra