My company has been running a GO tournament and since its around NCAA March Madness time I thought it'd be easy to find a site to manage the draw. I looked but couldn't find anything that did what I wanted so I wrote my own. Caveat: I just spent a few days on this and it could stand to be enhanced with more features and a rewrite of the ui implementation but I'm open to suggestions if anyone finds this useful.
To use it

My company has been running a GO tournament and since its around NCAA March Madness time I thought it'd be easy to find a site to manage the draw. I looked but couldn't find anything that did what I wanted so I wrote my own. Caveat: I just spent a few days on this and it could stand to be enhanced with more features and a rewrite of the ui implementation but I'm open to suggestions if anyone finds this useful.
To use it

फूल बड़े नाज़ुक होते है,
आते-जाते जब भी कभी पड़ती है नज़र,
कहीं किसी फूल पे,
तो बस खिल उठता है तन,
उस भीनी महक से,
और छा जाती है,
अजब सी ताजगी,
कितने रंग होते हैं ना फूलों के,
ऐसा ही एक रंग देखा था कहीं,
कुछ याद नही आ रहा ठीक-ठीक,
हल्का गुलाबी सा,
किसी चौराहे पे शायद,
हाँ, वहीं तो देखा था,
उन नन्हे से हाथों में,
रूखे-बिखरे बालों के झुरमुट में छिपी,
भोली सी आँखेंचमकती हुई,
धीमी सी आवाज़ में,
बड़े मनुहार से मुझसे पुछा था,
दीदी, लो ना -- ले लो न दीदी,
उन आँखों में झांकते हुए,
ख़याल आया मुझे,
काश मैं मांग सकती थोडी सी चमक इनकी,
और थोडी सी बचपन की लापरवाही भी,
थोड़े ही दिनों के लिए बस..उधार में,
और बदले में भर सकती इनके जीवन को,
इन्ही फूलों के रंग से,
दे सकती आशाओं की खुशबू,
और सींचती बगिया, इनके सुनहरे कल की,
यह दिवा-स्वप्न सजा के मैंने
बढाया ही था अपना हाथ,
के अकस्मात् ही चल पड़ी मेरी गाड़ी आगे की ओर,
और वो फूल पीछे ही छूट गए...
A good video on how Google's AdWords works. It is a very clever business model without compromising on user experience.
Have a look.
I read a very interesting article by someone who works for Yahoo about how he wrote a basic search engine in Ruby in just a few files. I wouldn't use this for a production system for as an example of how search engines work its fascinating and I plan to keep following his site to see how he enhances it
Description: http://blog.saush.com/2009/03/write-an-internet-search-engine-with-200-lines-of-ruby-code/
Source: http://github.com/sausheong/saushengine
... and he's got a really cool css/javascript formatter for the source in his blog. I've gotta learn more about SyntaxHighlighter
I read a very interesting article by someone who works for Yahoo about how he wrote a basic search engine in Ruby in just a few files. I wouldn't use this for a production system for as an example of how search engines work its fascinating and I plan to keep following his site to see how he enhances it
Description: http://blog.saush.com/2009/03/write-an-internet-search-engine-with-200-lines-of-ruby-code/
Source: http://github.com/sausheong/saushengine
... and he's got a really cool css/javascript formatter for the source in his blog. I've gotta learn more about SyntaxHighlighter
I came across this article titled Java as Legacy Language today. As an ex-Java guy who is now committed to Ruby I was amused by the title but also think he makes a good point.
One thing is for sure: If you're in the software development business, don't cling to old ways of doing development. And also, don't get too carried away thinking that something like Scrum is going to be the Bandaid that fixes your agility problems, because it may turn out that your main problem is Java itself. Keep an open mind. Try new things. Be ready when the next disruption arrives, or you may find yourself without a chair when the music stops.
I came across this article titled Java as Legacy Language today. As an ex-Java guy who is now committed to Ruby I was amused by the title but also think he makes a good point.
One thing is for sure: If you're in the software development business, don't cling to old ways of doing development. And also, don't get too carried away thinking that something like Scrum is going to be the Bandaid that fixes your agility problems, because it may turn out that your main problem is Java itself. Keep an open mind. Try new things. Be ready when the next disruption arrives, or you may find yourself without a chair when the music stops.
My colleague Pat Shaughnessy has spent a lot of time recently enhancing the auto_complete plugin. I suggest you read his blog posts and check out his fork of auto_complete on github to see the details.
I was reading his latest change to allow filtering of auto complete picklists and really like what he did but thought there was one thing that didn't quite feel right - the fact that you have to mix the application logic to filter the list with the plugin logic to find the list in the block in your controller.
Here's the code Pat wrote in his controller and what I'd like to avoid is having to re-implement the "LOWER(tasks.name) LIKE ?" portion that's already implemented in the filtered_auto_complete_for method of autocomplete.rb in the plugin.
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | find_options, params|
find_options.merge!(
{
:include => :project,
:conditions => [ "LOWER(tasks.name) LIKE ? AND projects.name = ?",
'%' + params['task']['name'].downcase + '%',
params['project'] ],
:order => "tasks.name ASC"
}
)
end
I'd like to propose a slight modification so the block you write as part of your application can focus just on the filtering and leave the responsibility for the search with plugin. I'm also proposing we use scopes (which I don't think were around when the original auto_complete plugin was written) to filter and sort the list the plugin. Here is the code I'd like to write in my application.
class ProjectController < ApplicationController
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | list, params |
list.by_project(params['project']['id'])
end
end
class Project < ActiveRecord::Base
named_scope :by_project,
lambda {|project_id| {:conditions => {:project_id => project_id} } }
end
We can do this with a simple modification of the plugin implementation of filtered_auto_complete_for
def filtered_auto_complete_for(object, method)
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }
@items = object.to_s.camelize.constantize.scoped(find_options)
@items = yield(@items, params) if block_given?
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
Originally, it used passed the find_options hash to the block and then executed the search in one step as "@items = object.to_s.camelize.constantize.find(:all, find_options)". My change is to rely on ActiveRecord proxy objects to chain criteria together leaving the block independent of the criteria here in the plugin. The best part is you don't have to worry about performance as ActiveRecord will intelligently combine the criteria into a single SQL request. For example searching for tasks that start with 'tas' within project #7
User Load (1.2ms) SELECT * FROM `tasks` WHERE ((`tasks`.`project_id` = '7') AND (LOWER(name) LIKE '%tas%')) ORDER BY name ASC LIMIT 10
My colleague Pat Shaughnessy has spent a lot of time recently enhancing the auto_complete plugin. I suggest you read his blog posts and check out his fork of auto_complete on github to see the details.
I was reading his latest change to allow filtering of auto complete picklists and really like what he did but thought there was one thing that didn't quite feel right - the fact that you have to mix the application logic to filter the list with the plugin logic to find the list in the block in your controller.
Here's the code Pat wrote in his controller and what I'd like to avoid is having to re-implement the "LOWER(tasks.name) LIKE ?" portion that's already implemented in the filtered_auto_complete_for method of autocomplete.rb in the plugin.
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | find_options, params|
find_options.merge!(
{
:include => :project,
:conditions => [ "LOWER(tasks.name) LIKE ? AND projects.name = ?",
'%' + params['task']['name'].downcase + '%',
params['project'] ],
:order => "tasks.name ASC"
}
)
end
I'd like to propose a slight modification so the block you write as part of your application can focus just on the filtering and leave the responsibility for the search with plugin. I'm also proposing we use scopes (which I don't think were around when the original auto_complete plugin was written) to filter and sort the list the plugin. Here is the code I'd like to write in my application.
class ProjectController < ApplicationController
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | list, params |
list.by_project(params['project']['id'])
end
end
class Project < ActiveRecord::Base
named_scope :by_project,
lambda {|project_id| {:conditions => {:project_id => project_id} } }
end
We can do this with a simple modification of the plugin implementation of filtered_auto_complete_for
def filtered_auto_complete_for(object, method)
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }
@items = object.to_s.camelize.constantize.scoped(find_options)
@items = yield(@items, params) if block_given?
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
Originally, it used passed the find_options hash to the block and then executed the search in one step as "@items = object.to_s.camelize.constantize.find(:all, find_options)". My change is to rely on ActiveRecord proxy objects to chain criteria together leaving the block independent of the criteria here in the plugin. The best part is you don't have to worry about performance as ActiveRecord will intelligently combine the criteria into a single SQL request. For example searching for tasks that start with 'tas' within project #7
User Load (1.2ms) SELECT * FROM `tasks` WHERE ((`tasks`.`project_id` = '7') AND (LOWER(name) LIKE '%tas%')) ORDER BY name ASC LIMIT 10
This story is about a man who once upon a time was selling Hotdogs by the roadside. He was illiterate, so he never read newspapers. He was hard of hearing, so he never listened to the radio. His eyes were weak, so he never watched television. But enthusiastically, he sold lots of hotdogs.
He was smart enough to offer some attractive schemes to increase his sales. His sales and profit went up. He ordered more a more raw material and buns and sold more. He recruited more supporting staff to serve more customers. He started offering home deliveries. Eventually he got himself a bigger and better stove. As his business was growing, the son, who had recently graduated from college, joined his father.
Then something strange happened.
The son asked, "Dad, aren't you aware of the great recession that is coming our way?" The father replied, "No, but tell me about it." The son said, "The international situation is terrible. The domestic situation is even worse. We should be prepared for the coming bad times."
The man thought that since his son had been to college, read the papers, listened to the radio and watched TV. He ought to know and his advice should not be taken lightly. So the next day onwards, the father cut down the his raw material order and buns, took down the colorful signboard, removed all the special schemes he was offering to the customers and was no longer as enthusiastic. He reduced his staff strength by giving layoffs. Very soon, fewer and fewer people bothered to stop at his Hotdog stand. And his sales started coming down rapidly and so did the profit. The father said to his son, "Son, you were right". "We are in the middle of a recession and crisis. I am glad you warned me ahead of time."
Moral of the Story: It's all in your MIND! And we actually FUEL this recession much more than we think.
I started receiving a lot of error notifications recently from my ExceptionNotfier plugin for an error with ActionController::InvalidAuthenticityToken. It turned out the error was occurring because one of my users was pasting a link to my app in an MS Office document and when Office sees the link it makes a request that Rails could not handle. Here I'll show you a simple fix you can use to avoid these errors with much credit going to an article at
Dealing with Microsoft Office Protocol Discovery in Rails
.
My execptions looked something like this (lots of boring details omitted)
A ActionController::InvalidAuthenticityToken occurred in events#1164:
ActionController::InvalidAuthenticityToken
[RAILS_ROOT]/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:86:in `verify_authenticity_token'
-------------------------------
Environment:
-------------------------------
* HTTP_USER_AGENT : Microsoft Data Access Internet Publishing Provider Protocol Discovery
* REQUEST_METHOD : OPTIONS
The problem is that Rails doesn't understand the method 'OPTIONS' (see rails/actionpack/lib/action_controller/routing.rb
#around line 270 of routing.rb
module ActionController
module Routing
HTTP_METHODS = [:get, :head, :post, :put, :delete]
end
end
Fixing the problem is fairly simple. You insert a before_filter into your application controller to intercept and handle requests with the option method before the rails code realizes it can't handle the request.
class ApplicationController < ActionController::Base
before_filter :options_for_microsoft_office_protocol_discovery
### Lots of code omitted
def options_for_microsoft_office_protocol_discovery
render :nothing => true, :status => 200 if request.method == :options
end
end
Its also easy to write a simple spec in rspec to verify the behavior. There is one trick which is that rails/actionpack/lib/action_controller/test_process.rb defines helper methods for get, post, put, delete & head that we can't use so we need to call the underlying method directly but the signature for that underlying method changed with Rails 2.3 (commit) so depending what version you're using you'll need one of 2 flavors.
# Rails 2.3 and above
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
process '/any/goofy/path', nil, nil, nil, 'OPTIONS'
response.should be_success
end
# Rails < 2.3 version
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
@request.env['REQUEST_METHOD'] = 'OPTIONS'
process '/any/goofy/path'
response.should be_success
end
You can also test from the command line using curl
curl -X OPTIONS http://localhost:3000/
Update: It turns out that Rails stores the acceptable methods in 2 different places actionpack/lib/action_controller/request.rb which does include all of get head put post delete options and also (see rails/actionpack/lib/action_controller/routing.rb which only includes :get, :head, :post, :put, :delete (options is missing). This means this fix will only work for OPTIONS requests and not any other type as ActionController::Request request_method will throw an exception before getting to the filter code above.
I started receiving a lot of error notifications recently from my ExceptionNotfier plugin for an error with ActionController::InvalidAuthenticityToken. It turned out the error was occurring because one of my users was pasting a link to my app in an MS Office document and when Office sees the link it makes a request that Rails could not handle. Here I'll show you a simple fix you can use to avoid these errors with much credit going to an article at
Dealing with Microsoft Office Protocol Discovery in Rails
.
My execptions looked something like this (lots of boring details omitted)
A ActionController::InvalidAuthenticityToken occurred in events#1164:
ActionController::InvalidAuthenticityToken
[RAILS_ROOT]/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:86:in `verify_authenticity_token'
-------------------------------
Environment:
-------------------------------
* HTTP_USER_AGENT : Microsoft Data Access Internet Publishing Provider Protocol Discovery
* REQUEST_METHOD : OPTIONS
The problem is that Rails doesn't understand the method 'OPTIONS' (see rails/actionpack/lib/action_controller/routing.rb
#around line 270 of routing.rb
module ActionController
module Routing
HTTP_METHODS = [:get, :head, :post, :put, :delete]
end
end
Fixing the problem is fairly simple. You insert a before_filter into your application controller to intercept and handle requests with the option method before the rails code realizes it can't handle the request.
class ApplicationController < ActionController::Base
before_filter :options_for_microsoft_office_protocol_discovery
### Lots of code omitted
def options_for_microsoft_office_protocol_discovery
render :nothing => true, :status => 200 if request.method == :options
end
end
Its also easy to write a simple spec in rspec to verify the behavior. There is one trick which is that rails/actionpack/lib/action_controller/test_process.rb defines helper methods for get, post, put, delete & head that we can't use so we need to call the underlying method directly but the signature for that underlying method changed with Rails 2.3 (commit) so depending what version you're using you'll need one of 2 flavors.
# Rails 2.3 and above
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
process '/any/goofy/path', nil, nil, nil, 'OPTIONS'
response.should be_success
end
# Rails < 2.3 version
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
@request.env['REQUEST_METHOD'] = 'OPTIONS'
process '/any/goofy/path'
response.should be_success
end
You can also test from the command line using curl
curl -X OPTIONS http://localhost:3000/
Update: It turns out that Rails stores the acceptable methods in 2 different places actionpack/lib/action_controller/request.rb which does include all of get head put post delete options and also (see rails/actionpack/lib/action_controller/routing.rb which only includes :get, :head, :post, :put, :delete (options is missing). This means this fix will only work for OPTIONS requests and not any other type as ActionController::Request request_method will throw an exception before getting to the filter code above.
Recently I came across this cool new feature from Google Labs about having your Gmail offline !