- I am looking for a modular framework where I can choose different ORM, different templating engine and so on where each component is developed independently by people who understand that specific area. As each of my project is very different sometimes I need the flexibility to change components. It was a great thing back in my Java times (Spring + Hibernate + Webwork).
- I really need an enterprise friendly dynamic language. Life's just too short to be wasting time trying to force a language to do things it's inventors don't consider important.
- I need a basic ecosystem of libraries (from XML, JSON, through excel, PDF, OO to image manipulation).
- I need a framework that supports TDD out of the box.
- I need a platform with (at least some) formal education and certification available. I need it because I employ people and certification really helped me back in Java times. To pass even the first Java certificate required people to study and to really understand the language and they simply took it as an independent measure of their skills.
- I need a language with a proper IDE. I use Vim every day - BUT not for programming. I've been using RubyMine for more than a month now and I feel like a blind man that got his eye sight back.
- I need reasonable deployment option - both scalable and resource efficient.
- Increasingly more important - I don't want the language/platform community to offend others
Entries Tagged 'Planet' ↓
Losing Faith
July 18th, 2009 — Planet
Extracting Data From MS Sql Server on MacOS
July 14th, 2009 — Planet
Restore database from backup
You will need a windows machine with MS Sql Server running (of course :-) Luckily, you can download it for free from here. Next connect to the database server using the command line utility osql (you will need to have it in your PATH)cd C:\Program Files\Microsoft SQL Server\MSSQL\Binn osql -EYou may need to create a new user:
use master go EXEC sp_addlogin 'peter', 'pass45' goNow let's have a look at the backup file (put it in some easy location so you don't have to type out the path):
Restore FILELISTONLY FROM DISK='c:\AMS.bak'This query allows us to find out the logical name of the database and log file which is needed to appropriately restore a database to a new path. What you get is basically an original location of the data and the log file. In my case I got:
AMS_Data D:\Program Files\Microsoft SQL Server 2000\MSSQL\data\AMS_Data.MDF AMS_Log D:\Program Files\Microsoft SQL Server 2000\MSSQL\data\AMS_Log.LDFWhich means that the original installation was on drive D:\. As my temp server is on C: I will have to recover with changing the locations of the files
RESTORE DATABASE ams FROM DISK='c:\AMS.bak' WITH MOVE 'AMS_Data' to 'C:\Program Files\Microsoft SQL Server\MSSQL\Data\ams.mdf', MOVE 'AMS_Log' to 'C:\Program Files\Microsoft SQL Server\MSSQL\Data\ams_log.ldf' goThe only important thing here is that 'AMS_Data' and 'AMS_Log' names match the ones from the previous query. Now you should hopefully see that your database has been restored. Now, will just get access to the database:
use ams go EXEC sp_grantdbaccess 'peter' go sp_addrolemember db_owner,peter goThere's more info on how to use osql here. Now we should be set to connect to the database from development machine. This was quite a number of steps just to restore the database - compared to createdb tmp; psql tmp <>Connecting to MS Sql from MacOS We will need to install and set up a couple of things:
sudo port install rb-dbi +dbd_odbc sudo port install freetdsset up connection to database
/opt/local/etc/freetds/freetds.confAdd your server to the end of the file:
[Ams] host = 192.168.11.106 port = 1433 tds version = 8.0where the host is IP of your windows machine. After this step you should be already able to connect to MS Sql Server:
tsql -S Ams -U peter -P pass45You should get the server database prompt (just like the osql on windows machine). You can try some commands like
use ams go select * from contacts goNow set up ODBC connection. Go to Applications -> Utils -> ODBC Administrator 1) add driver with following descriptions:
Description: TDS Driver File: /opt/local/lib/libtdsobdc.so Setup FIle: /opt/local/lib/libtdsobdc.so Define as: System2) add User DNS DSN: Ams Desc: old AMS database server add 2 keyword/value placeholders. To update them click on it and press TAB. Set it to following values:
ServerName: Ams (or whatever you set in freetds.conf) Database: ams (or whatever your database name)now you should be able to test iODBC. Note that I am using sudo for this as it doesn't seem to work without sudo complaining Data source name not found and no default driver specified. Driver could not be loaded (0) SQLSTATE=IM002.
sudo iodbctest "dsn=Ams;uid=USERNAME;pwd=PASSWORD"You should be now in interactive terminal again. Once all this works connecting from Ruby is really easy:
require 'rubygems'
require 'dbi'
DBI.connect('DBI:ODBC:ams', 'USERNAME', 'PASSWORD')
Rescuing the data
This is just a short ruby script I use to extract all the data from MS Sql and import it to Postgresql. It's not any functional database conversion - it's just to get the data out to something that's easier to work with and doesn't require windows machine running. It may have an issue with binary fields - it worked on most of them but it did choke on a couple of fields. DBI actually provides more metadata like NOT NULL attribute, primary key, etc. so the script could generate a more precise copy of the original database but this was enough for what I needed. You may run into unknown data type - especially if you try to import it to a different database engine - all you need to do is just update the method update_type to return correct mappings of the data types.
require 'rubygems'
require 'dbi'
require_library_or_gem 'pg'
def escape(text)
return "NULL" if text.nil?
text = PGconn.escape("#{text}")
return "'#{text}'"
end
def self.update_type(col)
type = col["type_name"]
type ||= 'timestamptz'
type = type.downcase
case type
when 'clob'
return 'varchar'
when 'varbinary'
return "oid"
when 'long varbinary'
return "oid"
when 'double'
return 'double precision'
when 'tinyint'
return 'smallint'
when 'char'
return "char(#{col['precision']})"
else
return type
end
end
dbh = DBI.connect("DBI:ODBC:ams", "peter", "pass45")
sth = dbh.prepare('select name from sysobjects where type = \'U\' ORDER BY NAME;')
sth.execute
tables = sth.collect{|row| row[0]}
tables.each do |table|
sth = dbh.prepare("select * from #{table} ")
sth.execute
create = "CREATE TABLE #{table}(\n"
create << sth.column_info.collect{|col| "\"#{col['name'].downcase}\" #{update_type(col)}"}.join(",\n")
create << ");\n\n"
puts create
sth.each do |row|
create << "INSERT INTO #{table} (#{sth.column_info.collect{|column| "\"#{column['name'].downcase}\""}.join(', ')}) VALUES (#{sth.column_info.collect{|col| escape(row[col['name']])}.join(', ')});\n"
end
create << "\n\n"
output = File.new("data_ams.sql", "ab+")
output.puts create
output.close
#puts create
end
To import the data to Postgresql is as simple as:
createdb ams_backup psql ams_backup <> noise.txt
Software Development as a Profession?
July 4th, 2009 — Planet
Software Development is Hard
June 27th, 2009 — Planet

The Talent Code
June 20th, 2009 — Planet
I read an interesting book couple of weeks ago. The Talent Code by Daniel Coyle. While the whole book is really good I particularly liked the section explaining the "sudden" appearance of extraordinary talents - like Brazilian football players, Bronte's sisters, Mozart, venetian sculptors and painters and so on. How it's believed that all those people were simply born with great talent and their great work just happened. And how the reality was almost a total opposite. The main idea behind the book is that no matter what you do, in order to achieve a world class skill you need to spend 10,000 hours in practice. The skill is basically "neural connections" in the brain. Those connections are created during practice but what determines the level of the skill is the "quality" of those connections. What increases the quality of the connection is myelin by insulating nerve fibers. The 10,000 hours is necessary to create sufficient myelin. What's interesting is that it's not just any practice - the best results are achieved in "deep practice".
The author goes on to explain how any of the great talents already had their 10,000 hours clocked in by the time they were "discovered". How bronte's sisters had written tens of training books before Jane Eyre or Wuthering Heights, how Mozart had his 10,000 hours of practice in very early age and how venetian painters and sculptors got their hours of training in apprenticeship. They were not born great but started from scratch and achieved their greatness by increasingly improving their skills. Interesting thing is that the apprenticeship didn't mean that they would simply paint the whole day and after 10 years became masters. No - they had to do all sorts of things - especially all sorts of "low level things" - like setting the canvas, preparing chisels and so on for their masters. Only after they learnt the basics could they move on to more difficult things. And this is what basically constitutes the "deep training" - choose a goal just outside your comfort zone and keep on failing until you achieve it. Then repeat the process.
To sidetrack a bit to IT - this is where I think today's system breaks down. Software development is hard. And it only starts with the technical skills - you still need to understand the domain (when working on accounting system you have to have a very solid understanding of accounting), you have to be able to work with people and translate their ideas and feelings about something they've never seen to reality. And there is no magic shortcut - you have to have your 10,000 hours clocked in before you can really do something. Programming is like writing - just like bronte's sisters - you have to write a lot a lot a lot and about everything you can find - only then your writing will start making sense. Unfortunately, I wouldn't really count any hours spent at school. Maybe it's an unfortunate situation around here - but the IT schools here are set to producing CIO's making decisions on a golf course rather than doing programing or any other actual IT work. To their defense that's pretty much what market here wants - most of the fresh grads from IT will find a good shake-leg work in a bank or MNC paying at least $10,000 per month. I meet quite a few of those people in my trainings or recently, as the banks scale down certain areas, in interviews.
Anyway, my point here was that only very very few people in IT are willing (or forced) to go through the whole journey - from setting up networks, installing computers, moving to servers, maintaining different operating systems, doing backup / recovery, working with databases, optimizing databases, writing SQL, programming in several languages for several years, understanding patterns going through several releases and so on. And none of that means "I used MS Access in 3rd semester".
Another interesting thing was the difference between masters and beginners. The difference was explained on chess players. The difference between chess masters and beginners is that masters can remember the whole board set up on one look. There is a twist, though. They could only remember the set up from an actual game. If the figures were in random order the chess masters photographic memory vanished. The reason why chess masters could remember the board setup from actual games is because they were not seeing the individual pieces - they were seeing the patterns.
I picked up the book because I wanted to know more about how people learn - I wanted to understand why after a year of training and working some of my employees are not able to do even a simple task, why is it that they spent a week installing a server without any success while somebody else can do the same work in 1 hour. Why some spend months and months programming a piece of functionality creating a total mess and somehow not "seeing" the simple solution that can be finished in a few hours or days. I used to be especially puzzled about the not seeing part. Even after showing them the simple solution they just couldn't understand it and had to go a big round of all possible wrong ways to arrive at the same solution. I guess some of them see patterns while others see thousands of lines of commands. As a result, in the light of the book's 10,000 hours I start to look very differently at this kind of things. The good news is: it's learnable. The bad news is: it may take 10 years for someone to learn it.
Dear Railsists, Please Don’t be Obtrusive
May 19th, 2009 — Planet
Update: thanks to Jon Wood aka jellybob, a prototype demonstration has been added, which is even better than my original jQuery btw as it degrades gracefully. Check it out in the ‘prototype-unobtrusive’ directory.
I am guessing 9 out of 10 of you reading the title is prepared for yet-another Rails drama on some obtrusive community members, and because everyone is tired of Rails dramas, I am risking that some of you won’t care to read the article - but I couldn’t resist :-). Actually I’d like to talk about usage of (un)obtrusive Javascript - why is it a bad idea to be obtrusive, especially given that (as you will learn from the article) writing unobtrusive Javascript is not harder, and you get the warm, fuzzy feeling of writing nice and clean code!
The Drill
To demonstrate the differences, I’ll lead you through the creation of a quick AJAXy shout wall both the default/standard (and obtrusive) way, then do the same with unobtrusive Javascript to show you that contrary to the popular belief, you don’t need to memorize the “Tome of Javascript Black Magick Tricks” by heart, use obscure libraries or special coding techniques to achieve clean, unobtrusive code. The shout wall is simply a form for posting a new message, and a list of messages below it, like so:
(You can check out the code used in this post from it’s github repository).
The Standard Way
Note: If you’d like to follow along, please use the provided pastie links - do not try to cut & paste multiple lines from the page (single lines are OK), as it will be b0rk3d.
-
Creating a new Rails application
rails obtrusive-shout-wall
- rails obtrusive-shout-wall
-
Get into the Rails dir
cd obtrusive-shout-wall
- cd obtrusive-shout-wall
-
Generate the resource message
script/generate resource message
- script/generate resource message
-
Add this the following to the generated migration (some_timestamp_create_messages (Get it from pastie):
t.string :author t.text :message
- t.string :author
- t.text :message
-
Run the migrations:
rake db:migrate
- rake db:migrate
-
Because we want to view the messages in reverse order (newest one first), we add a default scope to the Message model (in message.rb):
default_scope :order => 'created_at DESC'- default_scope :order => ‘created_at DESC’
-
Create the application layout - create a new file in app/views/layouts called application.html.erb, and fill it with the following content (Get it from pastie):
<%= stylesheet_link_tag "application" %> <%= javascript_include_tag :defaults %> <%= yield %>- <html>
- <head>
- <%= stylesheet_link_tag "application" %>
- <%= javascript_include_tag :defaults %>
- </head>
- <body>
- <%= yield %>
- </body>
- </html>
-
Create a file application.css and drop it into public/stylesheets. Add the following content (Get it from pastie):
body { background-color:#FFFFFF; color:#333333; font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif; margin:0 auto; padding:0; text-align:center; width:960px; } #messages { text-align: left; margin-left: 80px; margin-top: 50px; } #message-form { text-align: left; } #message-form dl { margin:10px 0 0 80px; } #message-form dd { color:#666666; font-size:11px; line-height:24px; margin:0 0 5px 80px; } #message-form dt { float:left; font-size:14px; line-height:24px; width:80px; text-align: left; } #author { margin-right: 640px; } #message { width: 600px; height: 200px; margin-right: 194px; } .message { margin-bottom: 20px; } .first_row { padding-bottom: 10px; } .message-meta { font-size: 12px; } .author { color: #FF5050; font-weight: bold; } .new-message-label { text-align: left; padding-top: 30px; margin-left: 80px; } #submit-button { float : right; margin-right: 195px; margin-top: 10px; }- body {
- background-color:#FFFFFF;
- color:#333333;
- font-family:"Lucida Grande",verdana,arial,helvetica,sans-serif;
- margin:0 auto;
- padding:0;
- text-align:center;
- width:960px;
- }
- #messages {
- text-align: left;
- margin-left: 80px;
- margin-top: 50px;
- }
- #message-form {
- text-align: left;
- }
- #message-form dl {
- margin:10px 0 0 80px;
- }
- #message-form dd {
- color:#666666;
- font-size:11px;
- line-height:24px;
- margin:0 0 5px 80px;
- }
- #message-form dt {
- float:left;
- font-size:14px;
- line-height:24px;
- width:80px;
- text-align: left;
- }
- #author {
- margin-right: 640px;
- }
- #message {
- width: 600px;
- height: 200px;
- margin-right: 194px;
- }
- .message {
- margin-bottom: 20px;
- }
- .first_row {
- padding-bottom: 10px;
- }
- .message-meta {
- font-size: 12px;
- }
- .author {
- color: #FF5050;
- font-weight: bold;
- }
- .new-message-label {
- text-align: left;
- padding-top: 30px;
- margin-left: 80px;
- }
- #submit-button {
- float : right;
- margin-right: 195px;
- margin-top: 10px;
- }
-
Create a new action, index in MessagesController (Get it from pastie):
def index @messages = Message.all end
- def index
- @messages = Message.all
- end
-
This goes into app/views/messages/index.html.erb (Get it from pastie):
Enter new message!
<% remote_form_for :message, :html => {:id => "message-form"} do |form| %>- Author:
- <%= text_field_tag 'author' %>
- Message:
- <%= text_area_tag 'message' %>
<%= render :partial => 'message', :collection => @messages %>We are showing the form for the messages and list the already exiting messages below the list. Note that we are using the _remote_form_for_ Rails helper to create an AJAXy form. This is already obtrusive, since if you observe the generated HTML, you will see that the form has an onsubmit parameter with some horribly looking code attached to it.:- <h3 class="new-message-label">Enter new message!</h3>
- <% remote_form_for :message, :html => {:id => "message-form"} do |form| %>
- <dl>
- <dt>Author:</dt>
- <dd><%= text_field_tag ‘author’ %></dd>
- <dt>Message:</dt>
- <dd><%= text_area_tag ‘message’ %></dd>
- </dl>
- <%= submit_tag "Submit!", :id => "submit-button"%>
- <% end %>
- <div id="messages">
- <%= render :partial => ‘message’, :collection => @messages %>
- </div>
Sure, you can go ‘meh’ all the way, but slinging Javascript code all over the place is just as bad idea as writing inline CSS (or even worse, using HTML code for styling) or putting Rails code into views. It will work without any problems - but it’s just not the right way of doing things, especially if your code is going to hit a certain size. -
You probably noticed that we are rendering a message as a partial - so create a partial file app/views/messages/_message.html.erb with the following content (Get it from pastie):
- <div class="message" id="message-<%=message.id%>">
- <div class="message-meta">on
- <%= message.created_at.to_formatted_s(:long_ordinal) %>,
- <span class="author"><%= message.author %></span>
- said:
- </div>
- <div><%= message.message %></div>
- </div>
-
We need a ‘create’ action in MessagesController in order to process the form submission (Get it from pastie):
def create @message = Message.create(:author => params[:author], :message => params[:message]) end
- def create
- @message = Message.create(:author => params[:author], :message => params[:message])
- end
-
And obviously we’ll need to render something to respond to the create action. Using the standard Rails way, RJS, we might come up with something like this (in app/views/messages/create.js.rjs - Get it from pastie):
page.insert_html :top, "messages", :partial => 'message', :object => @message page.visual_effect :highlight, "message-#{@message.id}"Here we insert the “messages” partial, using the just created @message, and throw a splash of yellow fade into the mix for good measure. Easy peasy.- page.insert_html :top, "messages", :partial => ‘message’, :object => @message
- page.visual_effect :highlight, "message-#{@message.id}"
- We are done! Fire up script/server, hit localhost:3000/messages and voila!
The Good Way
Here I am presenting only the steps that are different from the above - i.e. if step 3 is skipped, use the one from above.
-
Creating a new Rails application
rails unobtrusive-shout-wall
- rails unobtrusive-shout-wall
-
Get into the Rails dir
cd unobtrusive-shout-wall
- cd unobtrusive-shout-wall
- Same as above
- Same as above
- Same as above
- Same as above
- Since we are going to use jQuery (unobtrusiveness is *not* a property of jQuery, you can be just as unobtrusive with Prorotype -
but I switched to jQuery just before learning how, and now I am lazy to go backcheck out how in the ‘prototype unobtrusive’ directory in the github repository), you have to download jQuery with some basic effects, as well as an AJAX form handling library (still from the directory unobtrusive-shout-wall - Get it from pastie): - curl http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js > public/javascripts/jquery.js
- curl http://www.malsup.com/jquery/form/jquery.form.js?2.28 > public/javascripts/jquery-form.js
- curl http://view.jquery.com/tags/ui/latest/ui/effects.core.js > public/javascripts/effects.core.js
- curl http://view.jquery.com/tags/ui/latest/ui/effects.highlight.js > public/javascripts/effects.highlight.js
- <%= javascript_include_tag :defaults %>
- <%= javascript_include_tag ‘jquery’ %>
- <%= javascript_include_tag ‘jquery-form’ %>
- <%= javascript_include_tag ‘application’ %>
- <%= javascript_include_tag ‘effects.core’ %>
- <%= javascript_include_tag ‘effects.highlight’ %>
- Same as above
- Same as above
- Same as above - just delete “remote” from the name of the helper, i.e. use a standard Rails view helper, form_for
- Same as above
- Since we are not relying on Rails to do the rendering for as via a template file, we return the html chunk that we will render from Javascipt. So your create action should look like (Get it from pastie):
def create @message = Message.create(:author => params[:author], :message => params[:message]) render :partial => 'message', :object => @message end
- def create
- @message = Message.create(:author => params[:author], :message => params[:message])
- render :partial => ‘message’, :object => @message
- end
- Now comes the fundamentally different part - instead of using RJS to respond to the create action, we move all our code to application.js (Get if from pastie):
$(document).ready(function() { $("#message-form").ajaxForm({success: handleNewMessage}); function handleNewMessage(response, statusText) { $("#messages").prepend(response).effect("highlight", {}, 1500); } });I don’t think so that this code is particularly more complicated or hard to understand that the RJS one. Everything is inside the ready() function, which means that it’s only run once the document is properly loaded. Then we declare that “#message-form” is an AJAX form, and that upon successful submission, the handleNewMessage() method should be called. And if that happens, we add the response (which is the return value of the “create” action) to the “#messages” div, just as we did in RJS. Then we apply the yellow fade! w00t!- $(document).ready(function() {
- $("#message-form").ajaxForm({success: handleNewMessage});
- function handleNewMessage(response, statusText) {
- $("#messages").prepend(response).effect("highlight", {}, 1500);
- }
- });
- Same as above
curl http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js > public/javascripts/jquery.js curl http://www.malsup.com/jquery/form/jquery.form.js?2.28 > public/javascripts/jquery-form.js curl http://view.jquery.com/tags/ui/latest/ui/effects.core.js > public/javascripts/effects.core.js curl http://view.jquery.com/tags/ui/latest/ui/effects.highlight.js > public/javascripts/effects.highlight.js
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag 'jquery' %> <%= javascript_include_tag 'jquery-form' %> <%= javascript_include_tag 'application' %> <%= javascript_include_tag 'effects.core' %> <%= javascript_include_tag 'effects.highlight' %>
(You can check out the code used in this post from it’s github repository).
Conclusion
As you can see, the only real difference between the obtrusive and non-obtrusive version is in the last 2 points (downloading and including the jQuery header files can be easily solved with Rails templates): instead of leaving the rendering part to Rails, we return the response as a string and dynamically insert it from jQuery. With about the same effort, we kept all the Javascript code in application.js, which is much cleaner this way (you can open up 1 file and check out all the JS/AJAX behavior in one place), especially after introducing a lot of Javascript functionality into your code - in other words, for the same amount of work we got something much better. Please try to keep this in mind when you are working with Javascript and Rails the next time - believe me, it can save you from a lot of pain!
Rails 2.3 with Ruby 1.9
May 10th, 2009 — Planet

incompatible character encodings: UTF-8 and ASCII-8BITwhen data from database contain special characters. There are several patches available in lighthouse here and here but non of them really worked for me - safe for
contact.name.force_enconding('utf-8')4) send_data doesn't work on binary files with message invalid byte sequence in UTF-8. I used to use it for on the fly generated images but had to replace it with creating a temp file and then use
send_file
RailsBridge is Born
May 4th, 2009 — Planet, Uncategorized
I surely don’t have to introduce last week’s Ruby/Rails earthquake to anyone by now - it has been covered by a boatload of blogs (including this one), analyzed, argued over, rebutted, reddited, dugg and whatnot - suffice to say, it’s time to move on. It was a rather unpleasant drama piece, but fortunately it shed light on some problems the Ruby/Rails communities are facing, and (besides the ensuing trollfest and pointless arguing) it had a pleasant side-effect: a handful of people started to discuss how things could be made better, creating a small (and growing) but determined community: RailsBridge!
Say Hello to RailsBridge!
RailsBridge’s mission is “To create an inclusive and friendly Ruby on Rails community” (check out details on the homepage). Everyone is welcome to participate - with ideas, suggestions, design, code, new project proposals or just about anything that would make Rails a more open and accepted technology and community.
It’s very important to understand that we are not trying to form yet another oh-my-god-we-are-so-awesome Rails group of uber-hackers which looks down on everyone not in it’s ranks - for two reasons, at the very least:
- RailsBridge is open to anyone! - you don’t have to be a Rails core commiter, coder with 20 years of experience or a renowned Rails blogger - it’s enough if you’d like to make the Ruby/Rails scene more welcoming in any way
- We are trying to promote the exact opposite philosophy - we acknowledge that Rails’s image is somewhat tarnished because of the “rock star” attitude and we’d like to show by our actions that we are working on this and will eventually turn Ruby and Rails into a very welcoming and enjoyable community
Surely, this is quite a venture - our mission statement sounds great, but everyone can do the talking on just about whichever Gordian Knot out there, be it world hunger, world peace or friendly Rails. We’ll have to demonstrate that we mean serious business, and that’s why we need you - everyone’s ideas, insights and help matters! Check out the RailsBridge homepage to learn more about what are we up to and how to get involved.
File Downloads in Rails on Apache
May 2nd, 2009 — Planet
Over the past half a year we worked on several systems for logistics/courier/delivery companies. It was quite fun as a big logistics and inventory control system was my very first project when I arrived to Asia 9 years ago. Last week we launched one of them. It was slightly different as most of our systems are used mainly internally but this one is also used by clients of the courier company to book deliveries. Each delivery requires printing of confirmation documents, internal routing documents, then signed and stamped documents are uploaded back to the system as a proof of delivery for clients. It has quite a number of other (technically) interesting features like integration with google maps to geo-tag the orders and notifying drivers in the area - I'll write about it soon.
As this courier company handles several hundreds of deliveries every day it requires quite a number of uploads/downloads of documents and images. The issue with uploads and downloads is that they will tie up rails processes for much longer than usual requests. The problem is that rails processes are quite expensive in terms of memory (around 70 - 100MB for simple operations). Do 20 concurrent uploads/downloads and all your rails processes and memory will get tied up - and quite wastefully as there is no 'dynamic' processing during upload or download. The process just sits there and waits for the file to get delivered. Luckily there's a simple way how to move this burden to Apache. This kind of upload/download processes will take only around 2MB on average and your rails processes are free to handle the dynamic requests.
To let apache handle file downloads use x_sendfile. All you need to do is install x_senfile module on apache and adjust you config a little. Here's the installation instructions for Ubuntu 8.04:cd /usr/local/src wget http://tn123.ath.cx/mod_xsendfile/mod_xsendfile.c apxs2 -cia mod_xsendfile.cOpen apache config file and add the module line:
sudo vim /etc/apache2/apache2.conf
LoadModule xsendfile_module /usr/lib/apache2/modules/mod_xsendfile.soAdd the following 2 lines to your virtual host file
sudo vim /etc/apache2/sites-available/my_app
XSendfile on XSendFileAllowAbove onYou will have to restart the apache and you should be done:
sudo /etc/init.d/apache2 restartNow in your controller handling download add x_sendfile attribute and set it to true
send_file("/home/test/big_file.zip",
:filename => "big_file.zip",
:type => "application/zip,
:x_sendfile=> true)
The uploads are equally easy. You just need to apache modules libapreq2 and modporter.
wget http://mirror.nus.edu.sg/apache/httpd/libapreq/libapreq2-2.12.tar.gz tar -xzf libapreq2-2.12.tar.gz cd libapreq2-2.12 ./configure --with-apache2-apxs=/usr/bin/apxs2 make sudo make installNow download and install modporter. Get it from the github. Either use the download link and unzip or just clone the repository
git clone git://github.com/actionrails/modporter.git cd modporterOn Ubuntu I had to change reference to apxs in Rakefile as the in ubuntu it's apxs2.
vim RakefileChange the APXS line to the following:
APXS = "apxs2"No just run rake:
sudo rakeadd the following to your apache2.conf
sudo vim /etc/apache2/apache2.conf
LoadModule apreq_module /usr/lib/apache2/modules/mod_apreq2.so LoadModule porter_module /usr/lib/apache2/modules/mod_porter.soTo actually use it in your rails application you will need modporter plugin.
script/plugin install git://github.com/actionrails/modporter-plugin.gitAdd the following to the application_controller.rb (application.rb before Rails 2.3)
class ApplicationController < ActionController::Base mod_porter_secret = "secret" . .and just enable porter in you vhost file:
sudo vim /etc/apache2/sites-available/my_app
Porter On PorterSharedSecret secretAnd that's all now if you check the uploaded files they will be a ModPorter::UploadedFile Credit for this goes to Koz from theRailsWay.com - you can find more information here.
Rails *is* (still) a Ghetto
April 27th, 2009 — Planet

While I know the title is both asking for trouble (because of the now anecdotal original article with a similar title) and flamebaity, please read on - my goal is not to get some great stats but rather to know your opinion about the situation and discuss the possible solutions of the problem.
How it all started…
I would not like to re-iterate what has been said on several blogs, just to summarize: Matt Aimonetti, member of the Rails Activists, gave a presentation at GoGaRuCo which contained sexually explicit images (according to some - I am not here to judge whether that’s true, and it doesn’t matter anyway, as you’ll see in the rest of the post).
I am not really discussing whether it’s appropriate to have images of nude chicks in your presentation at a Ruby conference (I think it’s not, it’s unprofessional etc. - but that would be a matter of a different post Update: Someone summed this up in the article’s reddit thread nicely: If you’re a Rails programmer, or a Ruby programmer, and you don’t decry this sort of thing, you have no business calling yourself a professional. It doesn’t matter how large your website is, how easy it was to write, how much better it is over PHP or ASP.NET or J2EE; by definition, you do not belong to a professional community. That’s all there is to it. It’s incumbent on every Ruby programmer to either reject this sort of misogynistic sewage, or accept that you’re never going to advance the promotion of Rails in the public perception because members of the community still think it’s edgy or cool to put pictures of strippers in their public presentations. And here’s a hint: if your decided reaction is to talk about how unimportant this is, how much it doesn’t matter, or how much it doesn’t offend you personally, you probably don’t understand professionalism at all.) because sadly, I think there are far bigger problems here than that - shedding light on them is the real purpose of the article, not talking about pr0n at GoGaRuCo again.
Would You Walk Into a Hindu Temple with Your Shoes on?
I have been living in India for 2 months last summer, working on a Rails startup. Maybe I am odd or something, but I knew that I had to remove my shoes when entering a Hindu temple, and no one had to convince me (what’s more, I didn’t even think about it for a second) wether this is the right thing to do, why is it so, whether I should do otherwise etc. This is a similar situation - I just don’t do X when speaking at a conference, if I suspect that X makes feel even one person in the room uncomfortable, whether because of his gender, race, nationality, Ruby/Rails skills, penis size or what have you - regardless whether I think it’s fine for me, my wife, for other members of the community and/or the majority of the room.
The trick is, how does a hindu feel when I enter a temple in footwear (even if that is perfectly acceptable in my country, culture, family, friends) - it’s perfectly irrelevant how do I feel in the given situation. Using the previous paragraph, try to apply this to a Ruby/Rails conference.
Shit happens…
Until this point in the story, I see no problem at all, and could even agree with the guys asking “what’s wrong with you, don’t make a fuss out of nothing” - the pictures Matt used are non-problematic in my book, and he had no idea they are problematic in anyone’s book - theoretically it could have worked, but the point is, it did not. Some members of the Ruby community got offended, and here our story begins.
…and hits the fan
One of the real problems is that after this has been pointed out, Matt still keeps answering “As mentioned many times earlier, I don’t think my presentation is inappropriate.”. As I mentioned two paragraph above, it doesn’t matter what do you think, unless of course, you don’t care about offending some members of the community. In that case you should not try to apologize at all. However, if you are trying, reciting “I don’t think my presentation is inappropriate” will not put and end to the discussion. It just doesn’t work. Why can’t you just simply apologize, admitting that this was a bad move (because it offended some, not because porn, sexual images or whatever in presentations are bad, per se) and finish the discussion?
Rails is Still a Ghetto
However, in my opinion that’s still not the worst part of the story, or to put it differently, some members of the Rails community still found a way to make things worse, by applauding to all this:
OK, you say, we are all used to DHH’s style, this is just how the guy is. That’s (kind of) cool, but I heard that most of the Rails core team (and obviously Matt himself) has the same opinion - and that’s a much more serious problem, because it means that a Rails activist, backed by DHH and other Rails core members finds all this OK, despite of the fact that numerous people in the community voiced their opinion otherwise.
This is not about being a closed-minded prude, shouting for police and suing everyone using sexually explicit images in a presentation. This is not even about women, as I have seen both males and females on either side of the fence. This is about mutual respect - I don’t agree with you, but respect your feelings. Or not, as demonstrated in this case.
So Rails continues to be the most socially unacceptable framework - associated with arrogance, elitism and whatnot in the past - now add pr0n images in presentations. Thankfully RailsConf is held in Las Vegas, and that should calm down all the people who associate Rails with all this crap :-). The real problem is that people associate you with the tools you are using - think Cobol, PHP, Java… or Rails. By being part of the Rails community people associate me with Railsy stereotypes automatically, which aren’t nice at all right now.
I hear you, dear creme-de-la-creme Rails (core) member, I know you don’t give a shit, and you think this is all prude babbling - because your hourly rate is more than some of us earn in a day, and you’ll be sought after even if Rails will have a much worse image than it has now. But 99.9% of us are not in the ‘circle of trust’ and would be happier if Rails would not be constantly associated with a ghetto.
MINASWUBN
In case you are wondering what does the acronym stand for, it’s “Matz is Nice And So We Used to Be Nice”. Unfortunately, the stuff I don’t like about the Rails community is sneaking into Ruby too, it seems, as the above case demonstrates. Besides this, the count of aggressive comments and reactions on various blog posts is really disturbing to me. Please (at least Rubyists) try to avoid being contaminated by all this shit and stop thinking you are cool because you can swear on a forum (always in anonymity). You don’t have to be a douchebag just because you are a Rubyist / Rails coder, as surprising as this might sound to some.
Conclusion
I think “incidents” like this and getting more and more antisocial members are inevitable by-products of growth in a community. The questions is, whether, and if, how, do we stop them. The problem is that it seems to me the Rails “top management” doesn’t want to stop them (what’s more, even encourages them) in the first place (please prove me otherwise - maybe I don’t see the full story - I’ll be the happiest to admit that I am talking bullshit).
I have to admit I have no clue what would be the right move - burying our heads in the sand and pretending everything is fine is not. Please leave a comment if you have an idea or anything to add.