dynamic robots.txt file in Rails 3.x

April 27th, 2012 No comments

We have a need for dynamic handling of robots.txt file as we have different requirements for production, staging, dev, test, etc.

Google-fu shows various way to do this, some for Rails 2.x, some for Rails 3.x. Here is my version.

First is to edit config/routes.rb and add this line:


match '/robots.txt' => RobotsGenerator

Then add the following to app_root/lib/classes/robots_generator.rb.

NOTE: We have an old domain, foo.com, that redirects to our newfoo.com. We don’t want foo.com to get indexed, so I have special treatment for that in production

class RobotsGenerator
  # Use the config/robots.txt in production.
  # Disallow everything for all other environments.
  def self.call(env)
    req = ActionDispatch::Request.new(env)
    headers = {}
    body = if Rails.env.production?
      if req.host.downcase =~ /foo.com$/
        headers = { 'X-Robots-Tag' => "noindex,nofollow" }
        "User-agent: *\nDisallow: /"
      else
        File.read Rails.root.join('config', 'robots.txt')
      end
    else
        "User-agent: *\nDisallow: /"
    end

    [200, headers, [body]]
  rescue Errno::ENOENT
    [404, {}, "User-agent: *\nDisallow: /"]
  end
end

Finally, you want to move public/robots.txt to config/robots.txt.

I want to give credits to the people that inspired my version.

Categories: Rails, Ruby, Tech Tags: , ,

My Latest brites on Britely site

April 25th, 2012 No comments

Did you know that you can create your very own Brites? on Britely website


This should always contain the most up-to-date list of all the brites I created and published on Britely.

  • Dots Life
    • 5
  • Natural Disasters this century
    • 16
  • Yoda, teachings of
    • 41
Categories: Humor, Tech Tags: , , ,

Bingham High School 30th reunion

April 4th, 2012 No comments

Showing my age….

Bingham High school 30 year reunion is coming up on Aug 4th, 2012 (that’s this year folks). It will be from 6pm-9pm MST at Gardner Village, West Jordan, UT.

There is also a Facebook group for this.

Categories: Uncategorized Tags: ,

April 4th, 2012 No comments

The following has been making the rounds on Google+. I had a good laugh reading it, so wanted to share here.

=============================================

16 Things That it Took Me Over 50 Years to Learn (by Dave Barry)

1. Never, under any circumstances, take a sleeping pill and a laxative on the same night.
2. If you had to identify, in one word, the reason why the human race has not achieved, and never will achieve, its full potential, that word would be “meetings.”
3. There is a very fine line between “hobby” and “mental illness.”
4. People who want to share their religious views with you almost never want you to share yours with them.
5. You should not confuse your career with your life.
6. Nobody cares if you can’t dance well. Just get up and dance.
7. Never lick a steak knife.
8. The most destructive force in the universe is gossip.
9. You will never find anybody who can give you a clear and compelling reason why we observe daylight savings time.
10. You should never say anything to a woman that even remotely suggests that you think she’s pregnant unless you can see an actual baby emerging from her at that moment.
11. There comes a time when you should stop expecting other people to make a big deal about your birthday. That time is age eleven.
12. The one thing that unites all human beings, regardless of age, gender, religion, economic status or ethnic background, is that, deep down inside, we ALL believe that we are above average drivers.
13. A person, who is nice to you but rude to the waiter, is not a nice person (This is very important. Pay attention. It never fails.)
14. Your friends love you anyway.
15. Never be afraid to try something new. Remember that a lone amateur built the Ark. A large group of professionals built the Titanic.
16. Final thought for the day: Men are like fine wine. They start out as grapes, and it’s up to the women to stomp the snot out of them until they turn into something acceptable to have dinner with.

— Dave Barry

Categories: Uncategorized Tags: , ,

Blinkbooks – what-to-buy-him-a-gift-guide-for-women

March 23rd, 2012 No comments
Categories: Tech Tags: ,

ActionMailer SSLError hostname was not match with the server certificate

March 15th, 2012 No comments

So I am setting up a Continous Integration server using CruiseControl.rb and was getting these errors. I am on a RoR 3.1.x env and pointing to my local (same server) postfix for SMTP. I don’t need SSL.

OpenSSL::SSL::SSLError (hostname was not match with the server certificate):
/usr/lib/ruby/1.8/openssl/ssl.rb:123:in `post_connection_check’
/usr/lib/ruby/1.8/net/smtp.rb:582:in `tlsconnect’
/usr/lib/ruby/1.8/net/smtp.rb:562:in `do_start’
/usr/lib/ruby/1.8/net/smtp.rb:525:in `start’

http://scottiestech.info/2009/12/21/fixing-the-actionmailer-hostname-not-match-server-certificate-error/

Gave me a clue as to the problem. But adding this line

# Turn off auto TLS for e-mail
ActionMailer::Base.smtp_settings[:enable_starttls_auto] = false

to my config/environments/ci.rb does not work. I was still getting the same error. So poking around in ActionMailer gem source code gave me the last piece of clue I needed.

I also need to set this flag:

:openssl_verify_mode => false

Putting everything together,


ActionMailer::Base.smtp_settings[:openssl_verify_mode] = false
ActionMailer::Base.smtp_settings[:enable_starttls_auto] = false

is all I need. Turning off starttls is not needed, but I’d do it anyway because I am talking to my local SMTP server and don’t want the overhead.

google-spreadsheet-ruby and (Nokogiri::XML::XPath::SyntaxError)

March 13th, 2012 No comments

I have a Ruby script that update our Google Doc spreadsheet as part of releases. The script has been working for years, then suddenly started failing with errors like this one:


/usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:159:in `evaluate': Invalid expression: .//xmlns:link[@xmlns:@rel = 'http://schemas.google.com/spreadsheets/2006#cellsfeed'] (Nokogiri::XML::XPath::SyntaxError)
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:159:in `block in xpath'
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:150:in `map'
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:150:in `xpath'
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:214:in `css'
from /usr/local/lib/ruby/gems/1.9.1/gems/google-spreadsheet-ruby-0.1.6/lib/google_spreadsheet.rb:648:in `block in worksheets'
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node_set.rb:239:in `block in each'
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node_set.rb:238:in `upto'
from /usr/local/lib/ruby/gems/1.9.1/gems/nokogiri-1.5.2/lib/nokogiri/xml/node_set.rb:238:in `each'
from /usr/local/lib/ruby/gems/1.9.1/gems/google-spreadsheet-ruby-0.1.6/lib/google_spreadsheet.rb:646:in `worksheets'
from /home/tin/bin/google-spreadsheet:125:in `

'

It took a bit of sleuthing to find out that Nokogiri version 1.5.2 broke google-spreadsheet-ruby. Downgrading to v 1.5.0 made it work again.

I am documenting it here for those of you running into similar problems.

Addtions. It turns out nokogiri and google-spreadsheet gems are written by same author, and he is aware of the bug, but not fixing it at this time. He recommends using nokogiri v1.5.0

https://github.com/gimite/google-spreadsheet-ruby/issues/31#issuecomment-4451659

Google-fu show a solution, since I can’t keep gems from updating on my systems. I just have to force my script to request a particular version.

http://stackoverflow.com/questions/2693862/how-do-i-require-a-specific-version-of-a-ruby-gem

And here is how I solved my problem.


gem 'nokogiri', '=1.5.0'

require 'optparse'
require 'ostruct'
require 'csv'
require 'rubygems'
require 'nokogiri'
require 'google_spreadsheet'

Summary of Overcoming RoR Performance Challenges Meetup on Wed 2/29/12

March 1st, 2012 No comments

Overcoming RoR Performance Challenges Meetup

The talk was on best practices and some tips on looking for problems and how the panelists worked around them. There are no “magic” bullet like Ruby or RoR has :)

Essentials:

  1. Watch out when using ActiveRecord. It make it too easy to use DB. It make it too easy to use DB. One more time, it make it too easy to use DB.

    Essentially, ActiveRecord and DB is not always the right tool. Sometime using other tool could work better for a particular problem.

    Things mentioned:

    • Using Redis as a queueing system, to buffer writes, which later go to DB. (this is what Blitz, Bleacher Report use to increase their performance).
    • Use NoSQL (CouchBase, Mongo and Cassandara were mentioned as being used by panelists).
    • Cache results as much as possible. Don’t hit DB all the time.
    • Hand optimize queries might be needed. ActiveRecord is not the best at generating optimized DB calls.
  2. Cache as much as possible. Bleacher Reports put in caching layer everywhere, memcache, front end web cache, etc. They also have scripts that pre-warmed their cache (“goal is to never have users be the one who triggered a cache request”).

    Use the cache in newer RoR (3.2).

  3. Write code in ways that make it easy to update to latest Ruby and RoR.

    Ruby EE has flags to allow you to use more memory for internal cache. Sometime it make sense to test for and try different memory configuration there (based on 2 panelists’ experiences).RoR 3.2 has good Rack/Rails cache. Read the doc and use them.

  4. Background processes.
    • Use bg proc whenever possible.
    • Anytime you need to make calls to external website (external API), use a bg process, to not tie up your RoR web process.
    • Blitz put jobs into Redis queue, then bg server check Q for job, run it and put partial results back into Redis, Ajax call then check and format/display result to web client.
    • Bleacher Reports and Mixbooks also do similar things. They use Redis as a job queueing system, among other things (see 1 above).
  5. They all mention using other web server for production (not using webrick). The following were mentioned as being used by panelists.
    • Passenger
    • Thin
    • Unicorn
  6. Related to (ActiveRecord) above is the N+1 problem. Where you add 1 line of code and the DB calls increased manifold.
    • Advice essentially say to develop and use coding best practices and train developers to look out for them.
    • There is a possible test that can be use to automated looking out for N+1 issue.
    • Solving n+1 problem with special tests: http://en.oreilly.com/rails2009/public/schedule/detail/8615 Query testing – see PDF of slides page 75
    • Panelists all recommended RSpec for automated testing.
  7. Monitoring for issues and performance.
    • All panelists point to NewRelic as the tool they use all the time.
    • The host of the meeting Blitz also did a marketing spiel on their tool to use for performance testing (it look really good, and available as a plugin on Heroku). I am going to test it and see about using it for performance/load testing our site.
  8. For ease of scaling infrastructure, leverage AWS EC2, Heroku, Engine Yard and other cloud providers.

Errors while installing unicorn gem on OS X

February 2nd, 2012 No comments

I was updating my bundle for a rails 3.1 app, when I run into the following errors.

Installing unicorn (4.2.0) with native extensions
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

/opt/local/bin/ruby1.9 extconf.rb
checking for SIZEOF_OFF_T in ruby.h... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.

Provided configuration options:
--with-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/opt/local/bin/ruby1.9
/opt/local/lib/ruby1.9/1.9.1/mkmf.rb:381:in `try_do': The compiler failed to generate an executable file. (RuntimeError)
You have to install development tools first.
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:491:in `block in try_compile'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:443:in `with_werror'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:491:in `try_compile'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:686:in `macro_defined?'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:822:in `block in have_macro'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:790:in `block in checking_for'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:284:in `block (2 levels) in postpone'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:254:in `open'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:284:in `block in postpone'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:254:in `open'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:280:in `postpone'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:789:in `checking_for'
from /opt/local/lib/ruby1.9/1.9.1/mkmf.rb:821:in `have_macro'
from extconf.rb:4:in `

'

Gem files will remain installed in /Users/tin/.bundler/tmp/34826/gems/unicorn-4.2.0 for inspection.
Results logged to /Users/tin/.bundler/tmp/34826/gems/unicorn-4.2.0/ext/unicorn_http/gem_make.out
An error occured while installing unicorn (4.2.0), and Bundler cannot continue.
Make sure that `gem install unicorn -v '4.2.0'` succeeds before bundling.

And the mkmf.log contain this, which was the clue I needed.

"/usr/bin/gcc-4.2 -o conftest -I/opt/local/include/ruby-1.9.1/x86_64-darwin10 -I/opt/local/include/ruby-1.9.1/ruby/backward -I/opt/local/include/ruby-1.9.1 -I. -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -I/opt/local/include -pipe -O2 -arch x86_64 -fno-common conftest.c -L. -L/opt/local/lib -L/opt/local/lib -L. -L/opt/local/lib -arch x86_64 -L/usr/local/lib -lruby.1.9.1 -lpthread -ldl -lobjc "
i686-apple-darwin10-gcc-4.2.1: vfork: Operation timed out
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: int main() {return 0;}
/* end */

Notice the vfork: Operation timed out line? It turns out that I was running out of system resources (VM) and gcc can’t fork. Ah, my poor 8GB i7 laptop…. :-)

Fix was simple, I shutdown Firefox and Chrome w/their gadzillion windows and tabs opened. Then retried “bundle update” again, and voila!

Documenting it here in case other people run into similar problem.

Categories: OSX, Ruby, SW Dev, Tech Tags: , , , ,

Migrating from Bamboo to Cedar (calendon stack) on Heroku

November 17th, 2011 No comments

We just migrated from Bamboo (bamboo-ree-1.8.7) to Cedar (calendon rails 3.1 stack) on Heroku. Here are the steps I took to make it work. Note that I didn’t do the code migration, my dev handle that, I do the server and infrastructure part.

Basically this mean moving from Rails 2.x (and ruby 1.8.7) to Rails 3.1 (ruby 1.9.2). Some of the changes require upgrading gem packages. Things such as images, css and js has to be put into an asset bundle.

On the site itself, I left the old site running, e.g. oldsite.heroku.com, and created a new site at newsite.herokuapp.com.

We created a new git dev branch and pushed to newsite, e.g.

git push heroku dev:master

Since we use SSL, I have to make sure custom_domains addon is there. But…

heroku addons:add custom_domains:basic custom_domains:wildcard

I can’t add the ssl addon until I am ready, because Heroku requires that I defined the domains for the app first! Chicken and egg, as it mean I have to take down the currently running production site.

So, make sure everything is running on new site first. Because the next steps mean production site will be down during the changes.

0. Make sure your SSL cert is up-to-date and you have both part, domain.cert and private.key. And most importantly, your key is passphrase-less!

1. Make sure your DNS records are updated and have shortest possible TTL. You are changing them.

2. Wait till DNS changes (TTL) have settle, could be a few hours. Then update your production site CNAME from *.yourdomain.com to newsite.herokuapp.com.

3. Clear out the domains in your old Heroku site:

heroku domains:clear --app oldsite

4. Add domains to new site:

heroku domains:add '*.yourdomain.com' --app newsite
heroku domains:add 'www.yourdomain.com' --app newsite

5. Upload SSL cert to your new app:

heroku ssl:add yourdomain.crt private.key

6. Now you can add the ssl addon.

heroku addons:add ssl:hostname

7. You should get an email from Heroku that has the hostname for your SSL DNS record to point your DNS to. The name should be something like this:

appid1234567herokucom-1234567890.us-east-1.elb.amazonaws.com

Update your DNS CNAME for www.yourdomain.com to point to this name.

8. Test, test, and test again your spanking new site. Add the New Relic addon if you haven’t (life saver!) and monitor traffic to your new site.

9. Monitor the log of your new site:

heroku logs -t --app newsite

10. Check the processes:

heroku ps --app newsite

11. Wait a week, if everything look good, you can take down the oldsite.