tag:blogger.com,1999:blog-33995399702485977722024-02-06T23:33:35.361-08:00assert_buggyUnknownnoreply@blogger.comBlogger13125tag:blogger.com,1999:blog-3399539970248597772.post-38057379800233397752009-07-28T12:29:00.000-07:002009-07-28T12:37:32.350-07:00Moving to geekin.gsI'm moving my blog under a new domain <a href="http://geekin.gs">http://geekin.gs</a><br />If you've subscribed the RSS feed please do subscribe the new site feed.<br /><br />Thanks<br /><br />PaoloUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-3399539970248597772.post-15088229731721401502009-06-07T02:52:00.000-07:002009-06-21T05:06:33.673-07:00Install couchdb 0.9.0 and Erlang R13B from sources on ubuntu Jaunty 9.04I wanted to play with CouchDB 0.9.0 on Ubuntu Jaunty, and to do this I had to compile it from sources, and to be in sync with <a href="http://janl.github.com/couchdbx/">CouchDBX</a> I compiled as well erlang 13B.<br />This is the transcript of what I did.<br /><br /><h3><strong>Erlang</strong></h3><br />credits: <a href="http://ciarang.com/posts/compiling-erlang-on-ubuntu">ciarang.com</a><br /><h3>Dependencies</h3><br />install some dev packages<br /><pre><br />sudo apt-get install build-essential m4 libssl-dev libncurses-dev<br /></pre><br /><em>note:</em> if you need support for odbc, jinterface or wx you need to install their dependencies<br /><h3>Compiling</h3><br /><pre><br />wget http://erlang.org/download/otp_src_R13B.tar.gz<br />tar zxf otp_src_R13B.tar.gz<br />cd otp_src_R13B<br />./configure<br />make<br />sudo make install<br /></pre><br /><h3><strong>CouchDB</strong></h3><br />Credits: <a href="http://blog.james-carr.org/2009/05/01/installing-couchdb-090-on-ubuntu/">blog.james-carr.org</a><br /><h3>Dependencies</h3><br /><pre><br />sudo apt-get install libcurl4-openssl-dev libicu-dev libmozjs-dev<br /></pre><br /><h3>Compiling</h3><br /><pre><br />wget http://apache.mirroring.de/couchdb/0.9.0/apache-couchdb-0.9.0.tar.gz<br />tar zxf apache-couchdb-0.9.0.tar.gz<br />cd apache-couchdb-0.9.0<br />./configure --sharedstatedir=/var/local --localstatedir=/var/local<br />make<br />sudo make install<br /></pre><br /><h3>System configuration</h3><br />You need to create a user for couchdb<br /><pre><br />sudo useradd -d /var/local/lib/couchdb couchdb<br />sudo chown couchdb. /var/local/lib/couchdb<br />sudo chmod 750 /var/local/lib/couchdb<br /></pre><br />I prefer to have the logs in /var/log/couchdb and the pid in /var/run/couch.pid so let's edit the configuration file<br />in /usr/local/etc/couchdb/local.ini<br />edit the file so the log section looks as follows<br /><pre><br />[log]<br />file = /var/log/couchdb/couch.log<br /></pre><br />to edit the pid location we need to edit the file in /usr/local/etc/default/couchdb<br />this is how my file looks like<br /><pre><br />COUCHDB_USER=couchdb<br />COUCHDB_STDOUT_FILE=/dev/null<br />COUCHDB_STDERR_FILE=/dev/null<br />COUCHDB_PID_FILE=/var/run/couchdb.pid<br />COUCHDB_RESPAWN_TIMEOUT=5<br />COUCHDB_OPTIONS=<br /></pre><br />It's time to setup the init.d script<br /><pre><br />sudo cp -v /usr/local/etc/init.d/couchdb /etc/init.d/couchdb<br /></pre><br />we need to amend/etc/init.d/couchdb to set the permission of the pid file when the daemon starts<br /><br />you need to find the section<br /><pre><br /> if test -n "$COUCHDB_PID_FILE"; then<br /> command="$command -p $COUCHDB_PID_FILE"<br /> fi<br /></pre><br />and change it to<br /><pre><br /> if test -n "$COUCHDB_PID_FILE"; then<br /> touch $COUCHDB_PID_FILE<br /> chown $COUCHDB_USER. $COUCHDB_PID_FILE<br /> command="$command -p $COUCHDB_PID_FILE"<br /> fi<br /></pre><br />again we need to edit /etc/init.d/couchdb because the stop command won't work as it is<br />you need to find the "stop_couchdb" function at the line<br /><pre><br /> command="$COUCHDB -d"<br /></pre><br />and change it to<br /><pre><br /> command="$COUCHDB -d"<br /> if test -n "$COUCHDB_PID_FILE"; then<br /> command="$command -p $COUCHDB_PID_FILE"<br /> fi<br /></pre><br /><br />As a last step we want to create the directory for the logs<br /><pre><br />sudo mkdir /var/log/couchdb<br />sudo chown couchdb. /var/log/couchdb<br /></pre><br />And consequently set the log rotation in /etc/logrotate.d/couchdb<br /><pre><br />/var/log/couchdb/*.log {<br /> daily<br /> missingok<br /> rotate 52<br /> compress<br /> delaycompress<br /> notifempty<br /> create 640 couchdb adm<br /> sharedscripts<br /> postrotate<br /> [ ! -f /var/run/couchdb.pid ] || kill -USR1 `cat /var/run/couchdb.pid`<br /> endscript<br />}<br /></pre><br />And now is time to have some fun<br /><pre><br />/etc/init.d/couchdb start<br />curl 127.0.0.1:5984<br />curl 127.0.0.1:5984/test<br />curl -X PUT 127.0.0.1:5984/test<br />curl 127.0.0.1:5984/test<br />curl 127.0.0.1:5984/test/baz<br />curl -X PUT -d '{"foo":"bar"}' 127.0.0.1:5984/test/baz<br />curl 127.0.0.1:5984/test/baz<br /></pre><br /><br /><strong><em>Note:</em></strong> I just finished checking this installation process with the release candidate of couchdb 0.9.1 and it works fineUnknownnoreply@blogger.com2tag:blogger.com,1999:blog-3399539970248597772.post-88401097866718345282009-05-14T12:05:00.000-07:002010-01-17T05:14:03.537-08:00Amazon AWS SimpleDB a la carte with ruby and aws_sdb_bareAmong the Amazon Web Services or AWS if you prefer acronyms, <a href="http://aws.amazon.com/simpledb/">SimpleDB</a> is one of the less popular.<br /><br />I've been using this service it for a while in some personal projects using the aws-sdb, so far the only choice to deal with SimpleDB at a low level.<br /><br />Since I wanted to overcome some of the limits of aws-sdb I wrote a new gem <a href="http://github.com/hungryblank/aws_sdb_bare">aws_sdb_bare</a>.<br />Main feature of the gem are:<br /><br />* Complete implementation of SimpleDB api<br />* XML parsing uses Hpricot or Nokogiri<br /><br />And be free of chosing your HTTP connection library and strategy!<br /><br />You can use <a href="http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/index.html">Net::HTTP</a> or <a href="http://curb.rubyforge.org/">curb</a> or go concurrent using <a href="http://github.com/eventmachine/eventmachine/tree/master">eventmachine</a> or <a href="http://www.pauldix.net/2009/05/breath-fire-over-http-in-ruby-with-typhoeus.html">typhoeus</a> to manage your connections with sdb<br /><br />So just install it<br /><br /><pre><br />sudo gem install hungryblank-aws_sdb_bare -s http://gems.github.com<br /></pre><br /><br />And use the code in this <a href="http://gist.github.com/111897">gist</a> to get started, <a href="http://rdoc.elastastic.com/aws_sdb_bare/">rdoc are available</a>.<br /><br /><span style="font-weight:bold;">For a more complete overview of the SimpleDB ruby libraries currently available you should read <a href="http://geekin.gs/using-amazon-aws-simpledb-with-ruby-roundup">this article</a></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3399539970248597772.post-52026567528493823262009-05-11T02:08:00.000-07:002009-05-12T06:52:48.123-07:00RailsConf 2009 the "system" streamRailsConf 2009 finished few days ago and after a long trip back and some time to chill out I was going through the material of the conference and trying to connect some dots among the different topics which were covered.<br /><br />To give some background, I started my career as sysadmin (or linux geek, if you prefer) and because of that I like when custom software, whether it's a rails app or just a small script is seen in the context of an entire stack or as glue among heterogeneous systems.<br /><br />Well, this year's RailsConf made me happy including quite a few talks which had this kind of point of view, I'll list them here for my and other's reference.<br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/8505" class="url uid" name="session8505">The Gilt Effect: Handling 1000 Shopping Cart Updates per second in Rails</a><br />This presentation was brilliant, the guys at Gilt have a very interesting business model which translates in a really interesting technological challenge.<br />They use a solutions which combines ruby, rails, java and postgres to manage extreme peaks of traffic, as a note they measure their peak traffic in fractions of the amazon.com ecommerce website traffic!<br />Since they run time limited sales they leverage very well the EC2 pay per use scheme reducing to the minimum the size of their cluster in quiet periods and expanding it when the sale is on and customer really fights to get hold of the items Gilt offers.<br />It was the same time I've seen the cloud architecture leveraged in a completely spike driven business.<br />It's a shame that the slides of thi presentation aren't available yet.<br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/7879" class="url uid" name="session7879">PWN Your Infrastructure: Behind Call of Duty: World at War</a><br />These guys run several communities dedicated to popular games, they've been successful and they had to manage to scale their apps, they deploy a single app on multiple servers and they tried some different deployment and monitoring tools, and what they've found out is... the simpler tools are the best for the job they use shell scripting when shell scripting is enough, they deploy with <a href="http://github.com/opscode/chef/tree/master">chef</a> to manage their deployment process and monit <a href="http://mmonit.com/monit">monit</a> for monitoring. They developed an internal app to keep all the configuration together and aggregate monitoring infos.<br />I really enjoyed the "use the simpler tool for the job" philosophy they embraced, very hard core linux geek stuff. By the way the only piece of architecture they're looking to change is nfs, used to keep in sync their ruby/rubygems stack across machines.<br /><a href="http://en.oreilly.com/rails2009/public/schedule/proceedings">Slides are on the railscon website</a><br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/7966" class="url uid" name="session7966">Building a Mini-Google: High-Performance Computing in Ruby</a> Interesting talk very CS oriented, the speaker went through the publicly available docs for google page rank algorithm and in the presentations shows the theory behind it and the ruby code to actually implement it, very high quality content for a 45 mins talk.<br /><a href="http://en.oreilly.com/rails2009/public/schedule/proceedings">Slides are on the railscon website</a><br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/9108" class="url uid" name="session9108">Confessions of a PackRat</a><br />I've lost this one, can't find the slides on line.<br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/7897" class="url uid" name="session7897">Rube Goldberg Contraptions, Building Scalable Decoupled Web Apps and Infrastructure with Ruby</a> Really interesting talk, presenting a bunch of interesting technologies and solutions at once: deployment with <a href="http://github.com/opscode/chef/tree/master">chef</a>, computer cloud coordination and administration with <a href="http://github.com/ezmobius/nanite/tree/master">nanite</a> demoed live controlling all the notebooks in the room. Presentation on <a href="http://www.slideshare.net/ezmobius/railsconf">slideshare</a> but go and check out <a href="http://github.com/ezmobius/nanite/tree/master">nanite</a> on github now!<br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/7967" class="url uid" name="session7967">Art of the Ruby Proxy for Scale, Performance, and Monitoring</a><br />Missed this one, but slides are available on the <a href="http://en.oreilly.com/rails2009/public/schedule/proceedings">railsconf website</a> and some excerpt can be found on the speaker's <a href="http://www.igvita.com/2009/04/20/ruby-proxies-for-scale-and-monitoring/">blog</a>. Learn how to put small ruby proxies in front of your services to achieve better performances, adding load balancing, filtering and other really neat tricks using just ruby, EventMachine and other bits.<br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/6967">It's Not Always Sunny In the Clouds: Lessons Learned</a><br />Interesting talk about the problems of deploying your app on AWS infrastructure, really practical tips and tricks to run your app in the cloud, slides on<br /><a href="http://en.oreilly.com/rails2009/public/schedule/proceedings">railsconf website</a><br /><br /><a href="http://en.oreilly.com/rails2009/public/schedule/detail/8519" class="url uid" name="session8519">%w(map reduce).first - A Tale About Rabbits, Latency, and Slim Crontabs</a> Ok this was my talk so I'll skip any comment slides are <a href="http://www.slideshare.net/hungryblank/wmap-reducefirst-a-tale-about-rabbits-latency-and-slim-crontabs">on slideshare</a>.<br /><br />This is the end of this post railsconf wrap up, I hope it's been interesting and please leave comment if you find around the missing slidesUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-3399539970248597772.post-27983160008475358652009-03-14T14:57:00.000-07:002009-03-16T15:54:10.449-07:00consume web services like a ninja with eventmachine end event_utilsLately I spent some time using <a href="http://rubyeventmachine.com">eventmachine</a>, my main interest so far has been in the <a href="http://eventmachine.rubyforge.org/docs/DEFERRABLES.html">deferrables</a> and in writing clients to consume web services using them.<br /><br />In the process I ended up writing <a href="http://github.com/hungryblank/event_utils">event_utils</a> a gem that makes (or at least should) more intuitive to write clients based on eventmachine deferrables.<br /><br />Now let's start working at an example, first things first we need a web service to consume, our choice for this tutorial will be a dummy service named slowrand.<br /><br />If you hit the url http://slowrand.elastastic.com/?delay=1 you'll be served a random number between 0 and 9, the random number will be served after a delay of at least one second.<br /><br />So now that we have a web service to use, let's write a class that wraps the service.<br />Save the following as slow_rand.rb<br /><pre><br />class SlowRand<br /><br /> attr_accessor :value<br /><br /> include EM::Deferrable<br /> def initialize(delay = 1)<br /> client = EM::Protocols::HttpClient.request(<br /> :host => "slowrand.elastastic.com",<br /> :query_string => "delay=#{delay}")<br /> @value = nil<br /> client.callback do |response|<br /> self.value = response[:content].to_i<br /> puts "fetched value #{value} at #{Time.now}"<br /> self.succeed<br /> end<br /> client.errback { self.fail }<br /> end<br /><br /> def +(other)<br /> self.value + other.value<br /> end<br /><br /> def to_s<br /> value.to_s<br /> end<br /><br />end<br /></pre><br />Let's take a look at the code above<br /><br />In the initialize method we <br /><ol><br /><li>use the EM HttpClient to generate a request to slowrand</li><br /><li>we bind a callback to the request, in the callback we set the instance variable @value, we print some info on output and we set the deferred status of the slowrand object to succeeded</li><br /><li>we bind an errback to the request to have some feedback in case the request fails</li><br /></ol><br />the Slowrand class defines also a + method do add one slowrand to another and for convenience defines a to_s method<br /><br />ok now let's write client that fetches 2 slowrand and calculates the sum, the code will be<br /><br /><pre><br />require 'rubygems'<br />require 'event_utils'<br />require 'slow_rand'<br />include EventUtils<br /><br />in_deferred_loop do<br /> puts "started at #{Time.now}"<br /><br /> a, b = SlowRand.new, SlowRand.new<br /><br /> waiting_for(a, b) do<br /> sum = a + b<br /> puts "sum executed at #{Time.now}, #{a} + #{b} = #{sum}"<br /> end<br />end<br /></pre><br />Save the code above in client.rb<br />So, we initialize a deferred loop and print out the timestamp, after that we say to our client that he needs to wait for two slowrands to be fetched and only after that we execute the sum.<br /><br />The idea behind it is very simple a and b are 2 deferrables and will return instantly but the value of a and b will be defined only after the web service will reply, that's why we ask our deferred loop to wait, specifically it will be waiting until all the deferrables listed in waiting_for will have the deferred status set.<br /><br />Before running the client you need to install the eventmachine and event_utils gems<br /><pre><br />sudo gem install eventmachine<br />sudo gem install hungryblank-event_utils -s http://gems.github.com<br /></pre><br />and finally you can run the client<br /><pre><br />ruby client.rb<br /></pre><br />and you should see an output that looks like<br /><pre><br />started at Mon Mar 16 21:53:13 +0000 2009<br />fetched value 1 at Mon Mar 16 21:53:14 +0000 2009<br />fetched value 6 at Mon Mar 16 21:53:14 +0000 2009<br />sum executed at Mon Mar 16 21:53:14 +0000 2009, 1 + 6 = 7<br /></pre><br />Ok that's very little satisfaction but it takes little effort to make the client code more interesting.<br /><br />Save the following code in client_multi.rb<br /><pre><br />require 'rubygems'<br />require 'event_utils'<br />require 'slow_rand'<br />include EventUtils<br /><br />in_deferred_loop do<br /> puts "started at #{Time.now}"<br /><br /> a, b = SlowRand.new(3), SlowRand.new(3)<br /> c, d = SlowRand.new(2), SlowRand.new(2)<br /> e, f = SlowRand.new, SlowRand.new<br /><br /> waiting_for(a, b) do<br /> sum = a + b<br /> puts "== sum with delay 3 =="<br /> puts "sum executed at #{Time.now}, #{a} + #{b} = #{sum}"<br /> end<br /><br /> waiting_for(c, d) do<br /> puts "== sum with delay 2 =="<br /> sum = c + d<br /> puts "sum executed at #{Time.now}, #{c} + #{d} = #{sum}"<br /> end<br /><br /> waiting_for(e, f) do<br /> puts "== sum with delay 1 =="<br /> sum = e + f<br /> puts "sum executed at #{Time.now}, #{e} + #{f} = #{sum}"<br /> end<br />end<br /><br /></pre><br />So in this case we execute 3 sums, as in the client seen before but with a twist, in our code we setup first a sum of slowrands with a delay of 3 seconds, after one with a delay of 2 seconds and at last one with a delay of 1 second.<br /><br />After running our new client<br /><pre><br />ruby client_multi.rb<br /></pre><br />The output will look like<br /><pre><br />started at Mon Mar 16 21:57:48 +0000 2009<br />fetched value 0 at Mon Mar 16 21:57:50 +0000 2009<br />fetched value 2 at Mon Mar 16 21:57:50 +0000 2009<br />== sum with delay 1 ==<br />sum executed at Mon Mar 16 21:57:50 +0000 2009, 0 + 2 = 2<br />fetched value 8 at Mon Mar 16 21:57:51 +0000 2009<br />fetched value 6 at Mon Mar 16 21:57:51 +0000 2009<br />== sum with delay 2 ==<br />sum executed at Mon Mar 16 21:57:51 +0000 2009, 8 + 6 = 14<br />fetched value 8 at Mon Mar 16 21:57:52 +0000 2009<br />fetched value 8 at Mon Mar 16 21:57:52 +0000 2009<br />== sum with delay 3 ==<br />sum executed at Mon Mar 16 21:57:52 +0000 2009, 8 + 8 = 16<br /></pre><br />This is more interesting.<br />Because of the non blocking nature of eventmachine every sum has been performed as soon as possible.<br /><br />The sum of the slowrands with a delay of 1 second, which was written as last in our code did actually get executed first without waiting for the code above it to be executed.<br /><br />This example makes even more clear the advantages on the overall timing, the client fetched 2 slowrands with delay 1 second, 2 slowrands with delay 2 seconds and 2 slowrands with delay 3 seconds, a client that would fetch values sequentially would then spend at least 12 seconds to perform all the operations while in this case we spend about 4 seconds.<br /><br />In addition of a quicker overall processing we published the first result available after a bit more than one second while a client performing actions sequentially would have spent 6 seconds waiting before publishing anything.<br /><br />This example is more interesting if you think in terms of services with non predictable delays, without estimating what will happen first, you just need to specify what is needed to execute some specific code and let the events drive your code.<br /><br />Hoping to have provided some interesting ground to explore I'll finish saying thanks to all the people who contributed to eventmachine or wrote <a href="http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/">tutorials</a> that <a href="http://20bits.com/articles/an-eventmachine-tutorial/">helped</a> me in the process of learning.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-3399539970248597772.post-62093207690448571852009-01-26T13:18:00.000-08:002010-01-17T05:14:30.441-08:00Start using Amazon SimpleDB with ruby in 10 minutes<span style="font-weight:bold;">The information in this post is outdated, if you want a better complete overview of the SimpleDB ruby libraries you should read <a href="http://geekin.gs/using-amazon-aws-simpledb-with-ruby-roundup">this article</a></span><br /><br />Out there you can already find <a href="http://open.blogs.nytimes.com/2007/12/21/a-first-look-at-amazon-simpledb/">more</a> <a href="http://rug-b.rubyforge.org/svn/aws_sdb_proxy/">than</a> <a href="http://github.com/dysinger/aws-sdb/tree/master">one</a> project that lets you access Amazon SimpleDB using ruby.<br /><br />Since I wasn't really happy with any of them I started building my solution on top of <a href="http://github.com/dysinger/aws-sdb/tree/master">aws-sdb</a>.<br />Being really bad at naming projects I named my gem <a href="http://github.com/hungryblank/dead_simple_db">dead_simple_db</a>.<br /><br />To install the gem just type in your console<br /><br /><pre><br />sudo gem install hungryblank-dead_simple_db -s http://gems.github.com<br /></pre><br /><br />Here's how you can use it.<br /><br /><pre><br />require 'rubygems'<br />require 'dead_simple_db'<br /><br />#you need your Amazon AWS credentials defined in the environment<br /><br />ENV['AMAZON_ACCESS_KEY_ID'] = 'your access key'<br />ENV['AMAZON_SECRET_ACCESS_KEY'] = 'your secret access key'<br /><br />#Let's define a class that will use SimpleDb backend to store the instances<br /><br />class Client < DeadSimpleDb::Base<br /><br /> #Let's define the SimpleDb domain where the class will be stored<br /> domain 'test_domain'<br /><br /> #Add the definitions of the attributes we need to store<br /> attr_sdb :first_name, 'String'<br /> attr_sdb :last_name, 'String'<br /> attr_sdb :budget, 'Integer', :digits => 9<br /> attr_sdb :first_purchase, 'Time'<br /><br />end<br /><br />#and now is time to create the first object<br /><br />c = Client.new<br />c.first_name = "Henry"<br />c.last_name = "Chinaski"<br />c.budget = 1000<br />c.first_purchase = Time.now<br /><br /># that's how you save your first record on Amazon SimpleDB<br /><br />c.save<br /><br /># and that's how you fetch it<br /><br />henry = Client.find(:first, "['first_name' = 'Henry']")<br />puts henry.first_name<br /></pre><br /><br />Now this might be not exciting but it's been pretty easy, if you've time you can check that<br /><br /><pre><br />henry.first_purchase<br /></pre><br /><br />Is actually a Time object and not a string, dead_simple_db does the type casting for you so you don't have to worry if SimpleDb can store only strings.<br />For a similar reason the budget attribute has been defined with 9 digits, on the SimpleDB backend 1000 is stored ad "000001000" to allow the sorting as string to work properly with numbers.<br /><br />Note that dead_simple_db always stores in the records a 'class_name' attribute with the name of the class the record refers to, this allow you to store more than one class in the same domain.<br /><br />If you do store multiple classes in one domain, please remember to add the class_name to your queries to avoid weird results!<br /><br />So here you go you have no more excuses to not take a look a SimpleDB, is free and now it's simple to access it in a way that makes instantly sense.<br /><br />Planned improvements on the short term are<br /><br /><ul><br /> <li>Return query results with over 250 elements</li><br /> <li>Introduce support to QueryWithAttributes in find</li><br /> <li>Automatically add class_name filter to queries</li><br /></ul>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-3399539970248597772.post-53021118046638866932007-10-26T03:09:00.000-07:002007-11-27T07:21:25.133-08:00How to upgrade Ruby on Rails Restful routes to 2.0Ok, you were quite proud when on Rails 1.2.x you made your app restful.<br />Now in 2.0 REST has been improved cleaned reworked and... changed the naming of the nested Routes<br /><br />Let's take a look at the differences in 1.2.x<br /><br />the following code<br /><br /><pre><br />map.resources :dinners do |dinner|<br /> dinner.resources :dishes do |dish|<br /> dish.resources :side_courses<br /> end<br /> dinner.resources :drinks<br />end<br /></pre><br /><br />would generate (among many others)<br /><br /><pre><br /> dinners_url<br /> dinner_url<br /><br /> dishes_url<br /> dish_url<br /><br /> side_courses_url<br /> side_course_url<br /><br /> drinks_url<br /> drink_url<br /></pre><br /><br />and so on.<br />With the same code in the routes rails 2.0 generates<br /><br /><pre><br /> dinners_url<br /> dinner_url<br /><br /> dinner_dishes_url<br /> dinner_dish_url<br /><br /> dinner_dish_side_courses_url<br /> dinner_dish_side_course_url<br /><br /> dinner_drinks_url<br /> dinner_drink_url<br /></pre><br /><br />And your REST routes methods will change more if you use the new routes namespacing introduced with 2.0<br />This is good and much nicer, and is a great help in complicated applications that use the same resources at different nesting levels and for different purposes.<br /><br />But it means that to migrate from 1.2.x you've got to change many of your original calls to the *_url or *_path methods.<br /><br />Well, I wrote a small dodgy script to manage the search and replace of the old routes with the new ones.<br /><br />And I thought I'd share it...<br /><br />The script should run as it is on linux. It uses find/grep/sed system commands.<br /><br />first two steps are quite simple<br /><br /><ol><br /><li>upgrade a non critical copy of your rails app to version 2.0 of ruby on rails</li><br /><li>download the <a href="http://rails-20-routes-migrator.googlecode.com/svn/trunk/route_migrator.rb">script to migrate your routes from 1.2 to 2.0</a> and save it in the root directory of your rails project</li><br /><li>execute script/console and type the following<br /><pre><br />require 'route_migrator'<br /><br />RouteMigrator.dump_current_route_methods<br /></pre><br /></li><br /><li>exit from the console and open with a text editor the file route_map_2_0.rb. This file should contain a ruby hash with keys and values containing the old routes</li><br /><li>now you have to update the values of the hash with the new routes, for the previous example a line would look like<br /><br /><pre><br />"side_courses_url" => "side_courses_url"<br /></pre><br /><br />and you need to update it to<br /><br /><pre><br />"side_courses_url" => "dinner_dish_side_courses_url"<br /></pre><br /><br />If you don't have a clear idea about what the new routes are you can use<br /><pre><br />rake routes<br /></pre><br /><br />or open again script/console and type<br /><br /><pre><br />require 'route_migrator'<br /><br />RouteMigrator.dump_named_routes<br /></pre><br />Be aware of that the hash might contain some rubbish as keys, just delete the lines that you think aren't proper routes actually used in your applications,<br /></li><br /><li>When you think your hash is complete and ready to go you can check your work firing yet another time your script/console and typing<br /><pre><br />require 'route_migrator'<br /><br />RouteMigrator.check_new_routes<br /></pre><br />This will output a warning if you've typed in the hash some routes that are not in the list generated from 2.0<br /></li><br /><li>If the previous check succeeded you can try the following that will substitute every occurrence odf your old routes with the new ones<br /><span style="font-weight:bold;">WARNING: this script is guaranteed to screw up >>BADLY<< your code if you use it without understanding what it does. Read the source code of the script before proceeding. As always svn diff and svn revert will be your friends</span><br /><pre><br />require 'route_migrator'<br /><br />RouteMigrator.upgrade_route_methods!<br /></pre><br />At this point your application should be updated with the new routes<br /></li><br /></ol>Unknownnoreply@blogger.com6tag:blogger.com,1999:blog-3399539970248597772.post-2681770709968715892007-08-09T02:01:00.000-07:002007-08-09T02:21:22.255-07:00RMagick 2.0 beta released with memory control functionsYesterday was announced <a href="http://rubyforge.org/forum/forum.php?forum_id=16592">RMagick2.0.0 beta1 release</a>.<br /><br />Among others new features I've found interesting the "new methods to help control and monitor memory usage" I'm looking forward to playing with them when I'll be back from my holiday in late august.<br /><br />RMagick has been quite often considered prone to memory leaks, but it seems that <a href="http://groups.google.com/group/comp.lang.ruby/msg/a61984b06e70acea">memory leaks are not the actual cause of the high memory consumption of RMagick</a> it will be interesting to see what is now available to keep under control the memory used by this amazing library.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3399539970248597772.post-29648132697224713142007-07-26T04:36:00.001-07:002007-07-30T02:25:23.020-07:00google analytics problems?<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhnCZP8Sca7jFCxS_hltOWeF96iai7NGWmmQCJdx8-1YyeOgzJNW3FfH3XMR7QLl48MTio6q1UFxiQdEPTpSW1Q_uI63pnYS3CcKQPkzWahdleWCXKu3U0jog3pvMdD8QLINjcgJdjFH2O/s1600-h/Screenshot-5.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhnCZP8Sca7jFCxS_hltOWeF96iai7NGWmmQCJdx8-1YyeOgzJNW3FfH3XMR7QLl48MTio6q1UFxiQdEPTpSW1Q_uI63pnYS3CcKQPkzWahdleWCXKu3U0jog3pvMdD8QLINjcgJdjFH2O/s320/Screenshot-5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5091475497281636994" /></a><br /><br />Since yesterday google analytics seems to be experiencing problems.<br /><br />Some <a href="http://www.seroundtable.com/archives/014271.html">login problems</a> were experienced and <a href="http://analytics.blogspot.com/2007/07/notice-of-brief-processing-delay.html">a delay in the processing was announced</a>.<br /><br />Now in the dashboard I can see funny things like the image above (47 visits and no pageviews, quite a mistery). In the specific case the correct data should be 0 visits since I know yesterday there was no activity on that specific regexp-filtered profile.<br /><br />Statistics for july the 25th have stopped at 17 GMT for me.<br /><br />sh*t happens, at google too.<br /><br />-- update 30 july<br /><br />Today for some accounts <a href="http://groups.google.com/group/analytics-help-troubleshoot/browse_thread/thread/94acb7f4f84fe168/#" >google analytics data are delayed again</a>.<br />In my case data last update is 6.00 AM GMT july 29 so at the moment the delay is more than one day.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3399539970248597772.post-85700909363507887032007-06-06T15:23:00.000-07:002007-09-28T02:03:27.128-07:00ruby on rails params and empty stringsA little annoyance I've found using ruby on rails is the following:<br /><br />If in your model you have some strings that can be null, and the user doesn't fill the related fields in the web form, rails will end up storing an empty string "" instead of the good old NULL in the database.<br /><br />Now, this is for sure not a big problem but it has some <a href="http://dev.rubyonrails.org/ticket/3375">implications</a> that might affect the model validations and it can be even worse if the rails app is not the only program writing in the database, in this last case you easily end up with a mix of empty string and NULL values in the column making trickier to write queries conditions that involve that column.<br /><br />Now I was playing today to fix this problem and I came with a solution that uses <a href="http://simpledesc.rubyforge.org">SimpleDescriptor</a>.<br /><br />For any model that uses SimpleDescriptor as described <a href="http://assertbuggy.blogspot.com/2007/06/simple-descriptor-code-less-validate.html">in this post</a> the following is a way to have NULL saved in the database instead of the empty string ''<br /><br />first you need to define the clean_strings method<br /><br /><pre><br />def clean_strings<br /> self.class.described_as(:string).each do { |field| send("#{field}=", nil) if send(field) == '' }<br />end<br /></pre><br /><br />and then add the clean_strings method in your before_validation callback<br /><br /><pre><br />before_validation :clean_strings<br /></pre><br /><br />Starting from this moment your model will just save NULL instead of an empty string and the :allow_nil => true in the model validations will start behaving as expected.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-3399539970248597772.post-46004085817178188432007-06-04T11:06:00.000-07:002007-06-05T04:58:57.353-07:00Simple Descriptor, code less validate moreAfter 6 month I've released a new version of <a href="http://simpledesc.rubyforge.org/">Simple Descriptor</a>.<br /><br />This gem makes possible to attach some extra informations to a generic ruby class, but its mission is now includes specific methods to allow more control and flexibility on ActiveRecord validations, in addition to this, Simple Descriptor may help you in building a consistent approach in areas where rails doesn't.<br /><br />Let's start getting our hands dirty, first of all install the gem<br /><br /><pre><br />sudo gem install simple_descriptor<br /></pre><br /><br />after that you need to require the gem i.e in your config/environments.rb file<br /><pre><br />require 'simple_descriptor'<br /></pre><br /><br />now let's tweak our Employee ActiveRecord model<br /><br />the migration to create the Employee model will be<br /><pre><br />class CreateEmployees < ActiveRecord::Migration<br /> def self.up<br /> create_table :employees do |t|<br /> t.column :first_name, :string, :limit => 30, :null => false<br /> t.column :middle_name, :string, :limit => 10, :null => true<br /> t.column :last_name, :string, :limit => 30, :null => false<br /> t.column :gross_wage, :integer, :null => false<br /> t.column :personal_email, :string, :limit => 100, :null => false<br /> end<br /> end<br /><br /> def self.down<br /> drop_table :employees<br /> end<br /></pre><br />the basic model definition will be<br /><pre><br />class Employee < ActiveRecord::Base<br />end<br /></pre><br />to get some validations for free we need to add 2 lines of code<br /><pre><br />class Employee < ActiveRecord::Base<br /> extend SimpleDescriptor::ClassDescriptor<br /> validates_ar_descriptions<br />end<br /></pre><br />These 2 extra lines will<br /><ul><br /> <li>validates_presence_of every field defined as NOT NULL</li><br /> <li>validates_length_of every field defined with a limit</li><br /> <li>validates_numericality_of every field defined as anumber</li><br /></ul><br />but there some extra as well, fire the console of your rails app and type<br /><pre><br /> Employee.described_as :string<br /></pre><br />this will return all the fields defined as string in the database.<br />Now always in the console try<br /><pre><br /> Employee.maxlegth(:first_name)<br /></pre><br />this will return 30 which is the maximum length of the first_name field<br /><br />Or again you can have the list of the required fields<br /><pre><br />Employee.described_as :required<br />=> [:first_name, :gross_wage, :last_name, :personal_email]<br /></pre><br /><br />Or you can ask your model if specific field is required<br /><pre><br />Employee.describes? :first_name as => :required<br />=> true<br /></pre><br />If you want to inspect a bit more what's happening behind the scenes you can use<br /><pre><br /> Employee.descriptions<br /></pre><br />Now, let's say you have some different models i.e. Employee, Manager, Consultant and in all these models you have some sensible fields you want to show only to authorized people.<br /><br />If you use Simple Descriptor for all these models you can easily define which fields contains sensible informations, for the Employee it would be<br /><br /><pre><br />class Employee < ActiveRecord::Base<br /> extend SimpleDescriptor::ClassDescriptor<br /> validates_ar_descriptions<br /> describe :gross_wage as => :sensible<br />end<br /></pre><br />Starting from this moment you can ask the Employee class if a field is sensible or not<br /><pre><br />Employee.describes? :gross_wage, :as => :sensible<br />=> true<br /><br />Employee.describes? :first_name, :as => :sensible<br />=> false<br /></pre><br />Or you can obtain the list of sensible fields<br /><pre><br />Employee.described_as :sensible<br />=> [:gross_wage]<br /></pre><br />This may help you to manage sensible data show rules in your views or in your controller.<br /><br />To know more about Simple Descriptor you can just visit the online <a href="http://simpledesc.rubyforge.org/">docs</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-3399539970248597772.post-6633177337819934532007-05-17T15:03:00.000-07:002007-05-21T13:50:17.279-07:00ActiveRecord :select with :includeActiveRecord is an important slice of the joy included in Ruby on Rails, writing a SQL database driven application without actually writing any SQL is really pleasurable.<br /><br />But sometime, even in the joy you get some pain.<br />The pain for me arrived when I was working on some reporting feature that was pulling various data across a quite long chain of has_many relationships.<br /><br />I experienced a quite high load in the DB at the moment of the query and after that seconds of CPU full load eaten by my ruby process.<br />I checked what was going on in my log/development.log and I noticed the query was extracting all the columns of every table even if I specified a :select option, this turned a query originally quite light into a heavy one.<br /><br />I googled a bit and I found out <a href="http://dev.rubyonrails.org/ticket/5371">that</a> with ActiveRecord, if you specify :select and :include option you don't get anymore 100% joy but just 50%, your :select statement will be ignored.<br /><br />Today I'm trying to put back some percent of the joy.<br /><br /><a href="http://code.google.com/p/ar-select-with-include/">select_with_include</a> gem is meant to move the joy level up to 80% (no, not 100% yet)<br /><br />select_with_include will allow you to specify a limited :select statement like<br /><br /><pre><br />"table1.column1, table1.column3, table2.column2"<br /></pre><br /><br />or like<br /><br /><pre><br />"table1.*, table2.column3, table2.column4, talbe3.*"<br /></pre><br /><br />At the moment you can't specify functions or calculated fields. There are reason for that and I'm going to discuss these reason in the next posts. I'll try as well to explain how this gem works around the original ActiveRecord code.<br /><br />For the moment you're invited to get select_with_include gem using<br /><br /><pre><br />sudo gem install select_with_include<br /></pre><br /><br />and test it yourself specifying<br /><br /><pre><br />require 'select_with_include'<br /></pre><br /><br />in your config/environment.rb file.<br /><br />If you're a script/console user you can just try, while you<br /><pre><br />tail -f log/development.log<br /></pre><br />to launch the same find with :include and :select with and without requiring the gem.<br /><br />If you find any issue you're really welcome to use the <a href="http://code.google.com/p/ar-select-with-include/">issue tracker</a><br /><br /><br />And if you want to know more just stay tuned for the next postsUnknownnoreply@blogger.com7tag:blogger.com,1999:blog-3399539970248597772.post-38097552047111235382007-05-16T02:44:00.000-07:002007-05-21T15:00:44.620-07:00attachment_fu and Rmagick FAT thumbnailsI'm using attachment_fu on the project I'm currently working on, using it to process the images the users upload.<br /><br />As backend I use Rmagick, since it was already used in the same app. At some point I felt curious about the size in kb of the thumbnails generated, to estimate the increase of bandwidth the new feature would add on the server.<br /><br />I quickly spotted the size of the generated jpegs was unreasonable for the pixel size of them.<br /><br />It turned out that attachment_fu + Rmagick on Ubuntu 6.0.6 and Ruby 1.4 aren't compressing jpegs.<br /><br />To fix here's a one line patch on attachment_fu.<br /><br />this patch sets the jpeg quality to 85%<br /><br /><pre><br />[~]$ cat atch_fu/attachment_fu_rmagick_compression.patch <br />Index: lib/technoweenie/attachment_fu/processors/rmagick_processor.rb<br />===================================================================<br />--- lib/technoweenie/attachment_fu/processors/rmagick_processor.rb (revision 2864)<br />+++ lib/technoweenie/attachment_fu/processors/rmagick_processor.rb (working copy)<br />@@ -45,9 +45,9 @@<br /> else<br /> img.change_geometry(size.to_s) { |cols, rows, image| image.resize!(cols, rows) }<br /> end<br />- self.temp_path = write_to_temp_file(img.to_blob)<br />+ self.temp_path = write_to_temp_file(img.to_blob {self.quality = 85})<br /> end<br /> end<br /> end<br /> end<br />-end<br />\ No newline at end of file<br />+end<br /></pre>Unknownnoreply@blogger.com0