Code Digest #2

Posted about 7 years back at Revolution On Rails

When you program for a living, you write lots of code. There is often some code that you are fond of. We started the Code Digest series to present such code written by the RHG developers. We encourage other teams and individual developers to share similar snippets in their blogs so we all can learn from each other and become better rails developers.


Mai Nguyen


Simple AJAX error messaging

When simple javascript validation is not enough and your product managers insist on ajax for error messaging, guess what. You have to implement ajax error messaging. One such case is 'username availability'. This simple example displays an error message on blur of a the username field. It doesn't hit the server unless the value of the field is well-formed (at least that will save you *some* network traffic ...)

Controller would look something like:
class FooController < ::ApplicationController

def is_username_taken

unless Person.find_by_username(params[:username])
render :nothing => true
return
end

message_html_id = params[:message_html_id]
render :update do |page|
page.replace_html message_html_id ,"Username is not available, please choose another."
# if you want error styling associated with the failed state
page << "document.getElementById('" + message_html_id + "').className = 'failed'"
end

end

end



View would look something like:
<dl>
<dt><label>Username: </label></dt>
<dd id="username_input">
<%= text_field :person, :username, :class => "input", :type => 'text', :id => 'person_username_input' %>
</dd>
<dd id="username_messaging"><%= @person.errors.on(:username)%></dd>
</dl>



Your javascript would look something like:
var UserNameUnique = Class.create();
UserNameUnique.prototype = {
initialize: function( field_id, message_id) {
this.message_id = message_id;
this.field = document.getElementById( field_id );
if (typeof this.field == 'undefined') {return;}
// Observe blur on field
Event.observe(this.field, 'blur', this.checkName.bindAsEventListener(this));
},
checkName: function() {
if( typeof this.field != 'undefined' )
{
var name = this.field.value;
// don't hit server unless username is well-formed
var re = /^[A-Za-z])[a-zA-Z0-9]{2,25}$/;
if( name.match( re ))
new Ajax.Request('/foo/is_username_taken', {asynchronous:true, parameters:'username='+name+'&message_html_id='+this.message_id});
}
}
};

new UserNameUnique('person_username_input', 'username_messaging');


You could also use Rails helper observe_field instead of the writing your own javascript, but there is more flexibility in writing your own javascript (such as the need to check well-formed values before hitting the server).


Mark Brooks


Creating the options list for select tags can be annoying, especially if there is a requirement that the current "option" be displayed as the default option. With javascript, it isn't such a big deal, but one must take care of the degraded case as well.

In any event, the base object is an array of two-item hashes representing both the name of a video channel and the number of videos in that channel. By way of example:
@channelinfo = [
{"name"=>"Fitness","count"=>4},
{"name"=>"Diabetes", "count"=>1},
{"name"=>"Pregnancy", "count"=>11}
]



The option values are the name fields of each hash. The key is, we want the current option value to be the first one in the option list, and the rest to be in alpha order by name.

So let's create an option builder from the bottom up.

First, we only need the channel names for the select tag. This gives us what we need:
options = @channelinfo.collect { |channel| channel['name'] }


That gives us a list of channel names. Using the list above, it would be ["Fitness", "Diabetes", "Pregnancy"].

However, we need to make sure that the current channel is first in the list. Let's say that current channel is Diabetes. Since we already have that value in @current_channel, we can exclude it from our options list:
options = @channelinfo.collect do |channel|
channel['name']
end.reject do |channelname|
channelname == @current_channel
end



Now the resulting list will look like ["Fitness", "Pregnancy"]. However, we still need the current channel to be at the front of the lift, so we add it back as the first element:
options = @channelinfo.collect do |channel|
channel['name']
end.reject do |channelname|
channelname == @current_channel
end.unshift(@current_channel)



Now our options list looks like ["Diabetes", "Fitness", "Pregnancy"].

Two points. First, we want to make sure that, while the current channel is at the head of the list, the rest of the list items are in alpha order, so we add a sort directive in the appropriate place. Also, it is probably a good idea to exclude any nils that might pop up in the collection on the original data object, since it comes from a service and it is possible, however unlikely, that a hash might get spit out without a 'name' property. The more rigorous code looks like this now:
options = @channelinfo.collect do |channel|
channel['name']
end.compact.reject do | channelname |
channelname == @current_channel
end.sort.unshift(@current_channel)



Now we can generate our options list using:
options.collect do |channelname|
"<option>" + channelname + "</option>"
end.join(",")


although if you want to, you can simply combine the whole thing as follows:
@channelinfo.collect do |channel|
channel['name']
end.compact.reject do |channelname|
channelname == @current_channel
end.sort.unshift(@current_channel).collect do |channelname|
"<option>" + channelname + "</option>"
end.join(",")



to get the same result, and eliminate the unnecessary options binding.


Todd Fisher


Here is an extension trying to execute a block multiple times before giving up. Handy for network operations and such.

module Kernel
def could_fail(retries = 3, &block)
tries = 0
begin
yield
rescue Exception
tries += 1
if tries < retries
retry
else
raise
end
end
end
end


Call it as result = could_fail { some_operation_that_might_fail_first_time }

Todd Fisher


When you are writing a script that needs to auto install gems, you are likely to run into a problem that it stops because there are multiple platform versions available (jruby, win32, etc) and the gem command expects you to pick one that matches your platform. This patch forces to use a specific platform so no user interaction is needed. Original idea from Warren updated to support rubygems 0.9.4.

module GemTasks
def setup

return if $gems_initialized
$gems_initialized = true
Gem.manage_gems

# see => http://svn.bountysource.com/fishplate/scripts/debian_install.pl
Gem::RemoteInstaller.class_eval do

alias_method :find_gem_to_install_without_ruby_only_platform, :find_gem_to_install

def find_gem_to_install( gem_name, version_requirement, caches = nil )
if caches # old version of rubygems used to pass a caches object
caches.each {|k,v| caches[k].each { |name,spect| caches[k].remove_spec(name) unless spec.platform == 'ruby' } }
find_gem_to_install_without_ruby_only_platform( gem_name, version_requirement, caches )
else
Gem::StreamUI.class_eval do

alias_method :choose_from_list_without_choosing_ruby_only, :choose_from_list
def choose_from_list( question, list )
result = nil
result_index = -1
list.each_with_index do |item,index|
if item.match(/\(ruby\)/)
result_index = index
result = item
break
end
end
return [result, result_index]
end

end

find_gem_to_install_without_ruby_only_platform( gem_name, version_requirement )

end
end

end

end
end



Val Aleksenko


Since class-level instance variable are not inherited by subclasses, you need to go some extra steps when writing a plugin using them. Depending on the amount of such variables, I have been either defining a method instead of class-level instance variables or forwarding them to subclasses.

Example #1. acts_as_readonlyable needs to provide a single class level instance variable. Defining a method instead.

def acts_as_readonlyable(*readonly_dbs)
define_readonly_model_method(readonly_models)
end

def define_readonly_model_method(readonly_models)
(class << self; self; end).class_eval do
define_method(:readonly_model) { readonly_models[rand(readonly_models.size)] }
end
end



Example #2. acts_as_secure uses a bunch of variables. Forwarding them to subclasses.

def acts_as_secure(options = {})
@secure_except = unsecure_columns(options.delete(:except))
@secure_storage_type = options.delete(:storage_type) || :binary
@secure_class_crypto_provider = options.delete(:crypto_provider)
@secure_crypto_providers = {}
extend(ActsAsSecureClassMethods)
end

module ActsAsSecureClassMethods
def inherited(sub)
[:secure_except, :secure_storage_type, :secure_class_crypto_provider, :secure_crypto_providers].each do |p|
sub.instance_variable_set("@#{ p }", instance_variable_get("@#{ p }"))
end
super
end
end

Code Digest #2

Posted about 7 years back at Revolution On Rails

When you program for a living, you write lots of code. There is often some code that you are fond of. We started the Code Digest series to present such code written by the RHG developers. We encourage other teams and individual developers to share similar snippets in their blogs so we all can learn from each other and become better rails developers.


Mai Nguyen


Simple AJAX error messaging

When simple javascript validation is not enough and your product managers insist on ajax for error messaging, guess what. You have to implement ajax error messaging. One such case is 'username availability'. This simple example displays an error message on blur of a the username field. It doesn't hit the server unless the value of the field is well-formed (at least that will save you *some* network traffic ...)

Controller would look something like:
class FooController < ::ApplicationController

def is_username_taken

unless Person.find_by_username(params[:username])
render :nothing => true
return
end

message_html_id = params[:message_html_id]
render :update do |page|
page.replace_html message_html_id ,"Username is not available, please choose another."
# if you want error styling associated with the failed state
page << "document.getElementById('" + message_html_id + "').className = 'failed'"
end

end

end



View would look something like:
<dl>
<dt><label>Username: </label></dt>
<dd id="username_input">
<%= text_field :person, :username, :class => "input", :type => 'text', :id => 'person_username_input' %>
</dd>
<dd id="username_messaging"><%= @person.errors.on(:username)%></dd>
</dl>



Your javascript would look something like:
var UserNameUnique = Class.create();
UserNameUnique.prototype = {
initialize: function( field_id, message_id) {
this.message_id = message_id;
this.field = document.getElementById( field_id );
if (typeof this.field == 'undefined') {return;}
// Observe blur on field
Event.observe(this.field, 'blur', this.checkName.bindAsEventListener(this));
},
checkName: function() {
if( typeof this.field != 'undefined' )
{
var name = this.field.value;
// don't hit server unless username is well-formed
var re = /^[A-Za-z])[a-zA-Z0-9]{2,25}$/;
if( name.match( re ))
new Ajax.Request('/foo/is_username_taken', {asynchronous:true, parameters:'username='+name+'&message_html_id='+this.message_id});
}
}
};

new UserNameUnique('person_username_input', 'username_messaging');


You could also use Rails helper observe_field instead of the writing your own javascript, but there is more flexibility in writing your own javascript (such as the need to check well-formed values before hitting the server).


Mark Brooks


Creating the options list for select tags can be annoying, especially if there is a requirement that the current "option" be displayed as the default option. With javascript, it isn't such a big deal, but one must take care of the degraded case as well.

In any event, the base object is an array of two-item hashes representing both the name of a video channel and the number of videos in that channel. By way of example:
@channelinfo = [
{"name"=>"Fitness","count"=>4},
{"name"=>"Diabetes", "count"=>1},
{"name"=>"Pregnancy", "count"=>11}
]



The option values are the name fields of each hash. The key is, we want the current option value to be the first one in the option list, and the rest to be in alpha order by name.

So let's create an option builder from the bottom up.

First, we only need the channel names for the select tag. This gives us what we need:
options = @channelinfo.collect { |channel| channel['name'] }


That gives us a list of channel names. Using the list above, it would be ["Fitness", "Diabetes", "Pregnancy"].

However, we need to make sure that the current channel is first in the list. Let's say that current channel is Diabetes. Since we already have that value in @current_channel, we can exclude it from our options list:
options = @channelinfo.collect do |channel|
channel['name']
end.reject do |channelname|
channelname == @current_channel
end



Now the resulting list will look like ["Fitness", "Pregnancy"]. However, we still need the current channel to be at the front of the lift, so we add it back as the first element:
options = @channelinfo.collect do |channel|
channel['name']
end.reject do |channelname|
channelname == @current_channel
end.unshift(@current_channel)



Now our options list looks like ["Diabetes", "Fitness", "Pregnancy"].

Two points. First, we want to make sure that, while the current channel is at the head of the list, the rest of the list items are in alpha order, so we add a sort directive in the appropriate place. Also, it is probably a good idea to exclude any nils that might pop up in the collection on the original data object, since it comes from a service and it is possible, however unlikely, that a hash might get spit out without a 'name' property. The more rigorous code looks like this now:
options = @channelinfo.collect do |channel|
channel['name']
end.compact.reject do | channelname |
channelname == @current_channel
end.sort.unshift(@current_channel)



Now we can generate our options list using:
options.collect do |channelname|
"<option>" + channelname + "</option>"
end.join(",")


although if you want to, you can simply combine the whole thing as follows:
@channelinfo.collect do |channel|
channel['name']
end.compact.reject do |channelname|
channelname == @current_channel
end.sort.unshift(@current_channel).collect do |channelname|
"<option>" + channelname + "</option>"
end.join(",")



to get the same result, and eliminate the unnecessary options binding.


Todd Fisher


Here is an extension trying to execute a block multiple times before giving up. Handy for network operations and such.

module Kernel
def could_fail(retries = 3, &block)
tries = 0
begin
yield
rescue Exception
tries += 1
if tries < retries
retry
else
raise
end
end
end
end


Call it as result = could_fail { some_operation_that_might_fail_first_time }

Todd Fisher


When you are writing a script that needs to auto install gems, you are likely to run into a problem that it stops because there are multiple platform versions available (jruby, win32, etc) and the gem command expects you to pick one that matches your platform. This patch forces to use a specific platform so no user interaction is needed. Original idea from Warren updated to support rubygems 0.9.4.

module GemTasks
def setup

return if $gems_initialized
$gems_initialized = true
Gem.manage_gems

# see => http://svn.bountysource.com/fishplate/scripts/debian_install.pl
Gem::RemoteInstaller.class_eval do

alias_method :find_gem_to_install_without_ruby_only_platform, :find_gem_to_install

def find_gem_to_install( gem_name, version_requirement, caches = nil )
if caches # old version of rubygems used to pass a caches object
caches.each {|k,v| caches[k].each { |name,spect| caches[k].remove_spec(name) unless spec.platform == 'ruby' } }
find_gem_to_install_without_ruby_only_platform( gem_name, version_requirement, caches )
else
Gem::StreamUI.class_eval do

alias_method :choose_from_list_without_choosing_ruby_only, :choose_from_list
def choose_from_list( question, list )
result = nil
result_index = -1
list.each_with_index do |item,index|
if item.match(/\(ruby\)/)
result_index = index
result = item
break
end
end
return [result, result_index]
end

end

find_gem_to_install_without_ruby_only_platform( gem_name, version_requirement )

end
end

end

end
end



Val Aleksenko


Since class-level instance variable are not inherited by subclasses, you need to go some extra steps when writing a plugin using them. Depending on the amount of such variables, I have been either defining a method instead of class-level instance variables or forwarding them to subclasses.

Example #1. acts_as_readonlyable needs to provide a single class level instance variable. Defining a method instead.

def acts_as_readonlyable(*readonly_dbs)
define_readonly_model_method(readonly_models)
end

def define_readonly_model_method(readonly_models)
(class << self; self; end).class_eval do
define_method(:readonly_model) { readonly_models[rand(readonly_models.size)] }
end
end



Example #2. acts_as_secure uses a bunch of variables. Forwarding them to subclasses.

Jeffrey Damick


Introduction

This gem provides a metrics collecting for controllers, database queries, and specific blocks of code or methods. It is designed to be light-weight and have minimal impact on production builds while providing performance indicators of the running application.



Disclaimer

This software is released to be used at your own risk. For feedback please drop us a line at rails-trunk [ at ] revolution DOT com.
Using this plugin should not be your first step in application optimization/scaling or even the second one.



Example

class SomeClassToTest
collect_metrics_on :my_method

def my_method(blah = nil)
true
end
end


Output:
[ERROR] [2007-06-21 23:21:19] [trunk] [Metrics]|[76716]|[MysqlAdapter.log]|0.012727|args=["root localhost trunk_test", "CREATE DATABASE `trunk_test`"]
[ERROR] [2007-06-21 23:19:56] [trunk] [Metrics]|[35158]|[Request to [Test::SomeControllerWithMetricsId]]|0.001373|action = index|path =some?
[ERROR] [2007-06-21 23:19:56] [trunk] [Metrics]|[33676]|[SomeClassToUseModuleMixin.another_method]|0.000020|args=["also"]


for more samples and test cases see test/metrics_test.rb



Usage

The metrics are written to: logs/<environment>_metrics.log

Configuration can be updated in metrics/config/metrics.yml, you may copy this file to your RAILS_ROOT/config/metrics.yml and customize for your application, the RAILS_ROOT will be checked first.



Sample metrics.yml

production:
min_real_time_threshold: 1.0
single_line_output: true
some_module/test_controller: 0.0




Installation

As plugin:
script/plugin install svn://rubyforge.org/var/svn/metrics/trunk/vendor/plugins/metrics



License

metrics is released under the MIT license.



Support

The plugin RubyForge page is http://rubyforge.org/projects/metrics

[PLUGIN RELEASE] Metrics

Posted about 7 years back at Revolution On Rails


From Jeffrey Damick


Introduction

This gem provides a metrics collecting for controllers, database queries, and specific blocks of code or methods. It is designed to be light-weight and have minimal impact on production builds while providing performance indicators of the running application.



Disclaimer

This software is released to be used at your own risk. For feedback please drop us a line at rails-trunk [ at ] revolution DOT com.
Using this plugin should not be your first step in application optimization/scaling or even the second one.



Example

class SomeClassToTest
collect_metrics_on :my_method

def my_method(blah = nil)
true
end
end


Output:
[ERROR] [2007-06-21 23:21:19] [trunk] [Metrics]|[76716]|[MysqlAdapter.log]|0.012727|args=["root localhost trunk_test", "CREATE DATABASE `trunk_test`"]
[ERROR] [2007-06-21 23:19:56] [trunk] [Metrics]|[35158]|[Request to [Test::SomeControllerWithMetricsId]]|0.001373|action = index|path =some?
[ERROR] [2007-06-21 23:19:56] [trunk] [Metrics]|[33676]|[SomeClassToUseModuleMixin.another_method]|0.000020|args=["also"]


for more samples and test cases see test/metrics_test.rb



Usage

The metrics are written to: logs/<environment>_metrics.log

Configuration can be updated in metrics/config/metrics.yml, you may copy this file to your RAILS_ROOT/config/metrics.yml and customize for your application, the RAILS_ROOT will be checked first.



Sample metrics.yml

production:
min_real_time_threshold: 1.0
single_line_output: true
some_module/test_controller: 0.0




Installation

As plugin:
script/plugin install svn://rubyforge.org/var/svn/metrics/trunk/vendor/plugins/metrics



License

metrics is released under the MIT license.



Support

The plugin RubyForge page is http://rubyforge.org/projects/metrics

Ticketish Email Integration

Posted about 7 years back at benmyles.com - Home

Note: Also posted on the Integral Impressions blog.

One of the central features of Ticketish is email integration. Users can create new tickets by email and add comments to tickets by replying to any email that has the ticket id in the subject. I'll show how this integration is achieved, from setting up Postfix to writing the Ticket and Comment handlers.

Each project in Ticketish receives its own email address. The email address is in the format "[project.permalink]@[account.subdomain].ticketi.sh". Sending an email to the project's email address creates a new ticket. Once a new ticket is created, a notification email is sent. Replying to the notification email (or any further emails regarding the ticket) adds a comment to the ticket. Further, the user can add attachments to any emails and have them show up as attachments to a comment.

So, how does it work? Let's start with the big picture. The mail transfer agent Postfix runs on the same server as the Ticketish mongrels. Postfix receives mail for all ticketi.sh subdomains. When Postfix receives a new message, it fires up script/runner for Ticketish and passes the message in via STDIN. At this point we don't care if the project exists or not, that's for Rails to figure out. Postfix just needs to send any emails addressed to *.ticketi.sh to script/runner.

Let's dig a little deeper, and see how to accomplish this behavior with Postfix.

The first Postfix configuration file we'll look at is main.cf. I won't paste the whole file, just the interesting parts that differ from the default main.cf file Postfix comes with.


/etc/postfix/main.cf

myhostname = ticketi.sh
mydomain = ticketi.sh
mydestination = $myhostname, localhost.$mydomain,
localhost, regexp:/etc/postfix/mydestination


This is mostly straight-forward. We set the hostname and domain to "ticketi.sh". The interesting part is that we're using a regular expression lookup table with mydestination. The mydestination setting means "this is the final destination for the following domains". Obviously, we want to be the final destination for all Ticketi.sh domains, so we use a regular expression.


/etc/postfix/mydestination

/.*\.ticketi\.sh/ OK


Pretty simple. You need to make sure you generate the database file from that lookup table by running postalias:


# postalias /etc/postfix/mydestination
# ls /etc/postfix/mydestination.db
/etc/postfix/mydestination.db


Now that Postfix knows to receive mail for *.ticketi.sh, we need to tell it where to send that mail. First, we'll create a wrapper around script/runner that can receive incoming emails from Postfix.


/etc/postfix/ticketish_agent.sh

#!/bin/bash
HOME=/home/lsws /usr/bin/ruby \
/home/lsws/apps/ticketish/current/script/runner \
'data = STDIN.read; CommentHandler.receive(data) \
|| TicketHandler.receive(data)' 2>> \
/home/lsws/ticketish_agent.log


The actual Rails code in runner is pretty simple. We assign the incoming email to the data variable, and then do 'CommentHandler.receive(data) || TicketHandler.receive(data)'. This code tries to add the message as a comment first, but if the comment handler returns nil (as it will if the message isn't a comment) it'll create it as a new ticket instead.

Now we need to add a service to Postfix by adding a few lines at the bottom of master.cf.


/etc/postfix/master.cf

mailman unix - n n - - pipe
flags= user=lsws
argv=/etc/postfix/ticketish_agent.sh


We've just called the service "mailman" and it pipes the message through to the wrapper we just created. Note the user= field. As you might guess, this is the user the process runs as. Be sure to use the user your Rails application runs under.

Finally, we need to tell Postfix to deliver all local mail to this new service (all local mail, since Postfix is entirely dedicated to Ticketish). We do this by defining the local_transport in main.cf.


/etc/postfix/main.cf

local_transport = mailman


Creating the CommentHandler and TicketHandler is pretty simple. We just use the following structure:


ticketish/app/models/comment_handler.rb

class CommentHandler < ActionMailer::Base
def receive(email)
# ...
end
end


You can do whatever you like once you have the email. For example, to extract the project name and domain name from the recipient address of the email:


project_name, domain_name =
email.to.first.split("@")


So there you have it. Easy email integration with Postfix and Rails. If you haven't already heard of Ticketish, take a look. It's our new simple ticketing application, currently in beta. We're still sending out beta invites, so feel free to add your name.

Episode 48: Console Tricks

Posted about 7 years back at Railscasts

The Rails console is one of my favorite tools. This episode is packed with tips and tricks on how to get the most out of the console.

Thanks Akismet!

Posted about 7 years back at zerosum dirt(nap) - Home

I’m probably a bit behind the game on this one, but huge props are due to Akismet for making my blog life just a bit more pleasant. Before it was installed last week, I was deleting hoards of comment spam every day. Today, none.

In other blog-related news, I’m still planning on moving productions over to Mephisto, but have been hard pressed for time lately. Fortunately (when I get around to it), it has Akismet support baked right in.

UPDATE: finally moved over to a new blogging platform! About time, eh?

Episode 47: Two Many-to-Many

Posted about 7 years back at Railscasts

There are two different ways to set up a many-to-many association in Rails. In this episode you will see how to implement both ways along with some tips on choosing the right one for your project.

Hardware Accelerated Flash Video - the turning point?

Posted about 7 years back at work.rowanhick.com

I'm looking forward to the web 2.bomb era to be over. Every man and his dog is building yet another social networking, api enabled, ajaxified, beta tag wearing application and waiting for the VC money to flow in. Just follow techcrunch.com and yawn every morning at the yasu* of the day. Outside of the VC crazed crowd some interesting things are happening. Adobe's announcement on HD content deployed using the Flash Player is very interesting indeed, not so much from the feature set, but what it's actually doing technically. We now have a cross platform web delivered piece of code that is utilizing the GPU. I think this has been lost on a few people. I'm personally not interested in the HD aspect, what I am interested in is the hardware acceleration. If an appropriate DirectX or OpenGL piece of hardware is present it then the flash player will utilise it to enable full screen 'HD' video. Very very impressive. Tinic is a genius. This marks (in my mind) a turning point for web apps - the crack in the dam has started, finally we are starting to really break out of the limitations of the browser, and will pave the way for some serious development of serious web applications. Perhaps Flash will have the last laugh.. I am not a fan boy of any tech religion. I do not think Adobe are God, Microsoft know it all, or Rails will fulfill my every desire. However in unison it seems, people are looking for the (r)evolution - the race is currently on to see who can deliver this technology we're crying out for. Taking the real (engineering) enterprise to the web Back for one of the companies I worked for, we had a huge Delphi application that is a fat client, fat server model. A CAD/CAM app, it required lots of CPU cycles to render an entire window (real .. not the microsoft kind) structure, apply business rules etc, compared to your atypical order processing system (which are just fancy crud operations). Currently on the web, all you see are these crud applications. The so called web 2.0 era, for all of the applications we see, are really just crud systems. So nothing is there to support anything other than crud. Which rules out doing this particular app. The browser in it's next version is only just starting to see a Canvas object whereas this has been the backbone of many desktop applications for years/decades! Flash/Flex/Air notwithstanding of course... What gets me excited, is when the potential for an application like the previously mentioned CAD/CAM system to be delivered over the web, utilising the advantages of the web AND the advantages of the desktop. The only way of doing that is breaking out of the web browser sandbox to use a desktop's horsepower. I think this hardware acceleration development might just kick off a chain reaction. Imagine via Actionscript, suddenly being able to harness the GPU's drawing system.... or even processing for horribly complex calculations that suit for parallelism - instead of bringing your system to a crawl, pipe them off to your GPU. Think of the possibilities.... An interior design application, rendered in beautiful photo realism with all the lighting effects you could imagine, allowing you to design your dream interior and order everything for it online. Games, delivered online, using local client connections for rendering - all code, etc retained on the server and piped down on demand. Infinitely expansive as the code is never kept locally. Log back in the next day and all new baddies added into the game without you even knowing until you stumble upon one. User powered grid computing services. Imagine firing up your beast of a computer, connecting to medical research system, and donating your GPU cycles - without having to download any nasty java or activex applets to your desktop. Companies are salivating over the PS3's power for this and scrambling to figure out how to do it, imagine taking this to the desktop arena ? Is this not the Holy Grail we want ? Let's start imagining, dreaming up the possibilities... and if we're smart enough, try to realise them. My mind's already going a hundred miles an hour. What would you build if you had access to the best of both worlds ?! *yasu - Yet Another (......y) Start-Up

Roundtable: Women in Development II - Ruby on Rails Podcast

Posted about 7 years back at Ruby on Rails Podcast

Part II of a discussion with and about women in development.
See also:

Gentoo: Dependency info is missing!

Posted about 7 years back at benmyles.com - Home

After a clean Gentoo minimal install and emerge of a Ruby on Rails stack, Gentoo started throwing the following error when managing services via inet.d:


* Dependency info is missing! Please run
* # /sbin/depscan.sh
* to fix this.


Running /sbin/depscan.sh seemed to have no effect.

I tracked down a post from a mailing list that explains what's going on.

In a nutshell, my /var/lib/init.d/deptree file was empty. I'm still not sure why. The /sbin/depscan.sh command rebuilds this file, but not if it's newer than some configuration file in /etc. The answer is to rm /var/lib/init.d/deptree and then run /sbin/depscan.sh.

If you get any errors about /bin/mktemp not existing, make sure to emerge mktemp.

Easy solution, but quite obscure!

Episode 46: Catch-all Route

Posted about 7 years back at Railscasts

Sometimes you need to add complex/dynamic routes. This is often impossible to do in routes.rb, but do not worry. It can be accomplished with a catch-all route. See how in this episode.

Tumbleranting

Posted about 7 years back at zerosum dirt(nap) - Home

Seth Godin is a nicer guy than I am (he’s probably better dressed, too): I would have ballparked his quote a little higher. Explanation: there’s a “don’t waste my time” fee.

As a freelancer, this happens to me all the time and it’s muy frustrating. I like hearing ideas, I like helping you structure your approach, I love developing solutions, applications, tools for you. I don’t even mind giving estimates and free advice. But in order to do that, you need to tell me what it is you want.

And no, “just like digg but with/for xxx” isn’t what I’m talking about :-).

Code Digest #1

Posted about 7 years back at Revolution On Rails

When you program for a living, you write lots of code. There is often some code that you are fond of. We start the Code Digest series to present such code written by the RHG developers. We encourage other teams and individual developers to share similar snippets in their blogs so we all can learn from each other and become better rails developers.

Daniel Silva



<%= link_to(image_tag("/images/icon.gif", :style=>"padding-right:0px;"), {:controller => '/registration', :action => 'login', :dest => request.request_uri}, {:style => ""}) %> 

With this line, I can create an image link using Rails code, to take advantage of the power of routes in Rails while still creating this kind of structure: <a href="#"><img border="0"/></a>



Jack Dempsey



Ok, so here's something useful for using keyboard short cuts to navigate through a small supporting application:
def include_keyboard_shortcuts

hotkey = 'Ctrl+Shift'
code_string = ''
keys = {
'm'=>'/account_info/show',
's'=>'/account_info/index',
'c'=>'/menu/go?menu_action=new_customer',
'p'=>'/products',
'o'=>'/account_info/orders',
't'=>'/order_tracker',
'x'=>'/auth_sessions/destroy',
'r'=>'/current_users/reset_password'
}

current_user_needed = %w{m o r}

keys.each_pair do |k,v|
next if current_user_needed.include?(k) && current_user.nil?
code_string << "shortcut('#{hotkey}+hm#{k}',function() { document.location.href='#{v}' });\n"
end

javascript_tag(code_string)

end



Then in a layout file just:
<%= javascript_include_tag 'shortcuts' %>
<%= include_keyboard_shortcuts %>



Makes use of a nice shortcuts.js lib.


Val Aleksenko


This is a fragment of a conversation on our internal IRC with my solution for refactoring a piece of code:
May 07 14:07:56 <Anthro> There has to be a better way to do this (x and y are non-negative integers): increment = (x!=0) ? ( (y!=0) ? 0 : 1 ) : -1
May 07 14:08:22 <Anthro> I think it can be done with math instead of logic.
May 07 14:16:56 <jack> Anthro: have you thought about using sin and cos? ;-)
May 07 14:18:42 <muzzy> (x <=> 0) <=> (y <=> 0)



Granted, it is not as clear as the original, but it is hard to resist it from the aesthetic point of view.

Val Aleksenko


I love writing dynamically generated methods and classes in Ruby as the next guy. When I was writing acts_as_readonlyable, I needed to manage multiple connections. I found that the easiest solution for managing active connections was generation of an AR class for each read-only definition and borrowing the connection from it. The usage is acts_as_readonlyable :read_only_entry_in_database_config.
def acts_as_readonlyable(readonly_db)
define_readonly_class(readonly_db) unless ActiveRecord.const_defined?(readonly_class_name(readonly_db))
end

def readonly_class_name(db)
"Generated#{ db.camelize }"
end

def define_readonly_class(db)
ActiveRecord.module_eval %Q!
class #{ readonly_class_name(db) } < Base
self.abstract_class = true
establish_connection configurations[RAILS_ENV]['#{ db }']
end
!

end



Warren Konkel


The ConfigFile class is a quick and easy way to load YAML files located in your Rails application's config directory. Simply place a YAML file into your config directory and then access it like a hash. For example this will read your config/database.yml: ConfigFile['database']['production']['adapter'].
class ConfigFile
def self.[](arg)
@@cached_configs ||= {}
@@cached_config_mtimes ||= {}

base_name = "config/#{arg}.yml"
filename = File.join(RAILS_ROOT, base_name)
raise "ERROR: Config not found: #{base_name}" unless File.exists?(base_name)

if @@cached_configs[arg].nil? || @@cached_config_mtimes[arg] < File.stat(filename).mtime.to_i
@@cached_configs[arg] = YAML.load(File.open(filename))
@@cached_config_mtimes[arg] = File.stat(filename).mtime.to_i
end

@@cached_configs[arg]
end
end

Code Digest #1

Posted about 7 years back at Revolution On Rails

When you program for a living, you write lots of code. There is often some code that you are fond of. We start the Code Digest series to present such code written by the RHG developers. We encourage other teams and individual developers to share similar snippets in their blogs so we all can learn from each other and become better rails developers.

Daniel Silva



<%= link_to(image_tag("/images/icon.gif", :style=>"padding-right:0px;"), {:controller => '/registration', :action => 'login', :dest => request.request_uri}, {:style => ""}) %> 

With this line, I can create an image link using Rails code, to take advantage of the power of routes in Rails while still creating this kind of structure: <a href="#"><img border="0"/></a>



Jack Dempsey



Ok, so here's something useful for using keyboard short cuts to navigate through a small supporting application:
def include_keyboard_shortcuts

hotkey = 'Ctrl+Shift'
code_string = ''
keys = {
'm'=>'/account_info/show',
's'=>'/account_info/index',
'c'=>'/menu/go?menu_action=new_customer',
'p'=>'/products',
'o'=>'/account_info/orders',
't'=>'/order_tracker',
'x'=>'/auth_sessions/destroy',
'r'=>'/current_users/reset_password'
}

current_user_needed = %w{m o r}

keys.each_pair do |k,v|
next if current_user_needed.include?(k) && current_user.nil?
code_string << "shortcut('#{hotkey}+hm#{k}',function() { document.location.href='#{v}' });\n"
end

javascript_tag(code_string)

end



Then in a layout file just:
<%= javascript_include_tag 'shortcuts' %>
<%= include_keyboard_shortcuts %>



Makes use of a nice shortcuts.js lib.


Val Aleksenko


This is a fragment of a conversation on our internal IRC with my solution for refactoring a piece of code:
May 07 14:07:56 <Anthro> There has to be a better way to do this (x and y are non-negative integers): increment = (x!=0) ? ( (y!=0) ? 0 : 1 ) : -1
May 07 14:08:22 <Anthro> I think it can be done with math instead of logic.
May 07 14:16:56 <jack> Anthro: have you thought about using sin and cos? ;-)
May 07 14:18:42 <muzzy> (x <=> 0) <=> (y <=> 0)



Granted, it is not as clear as the original, but it is hard to resist it from the aesthetic point of view.

Val Aleksenko


I love writing dynamically generated methods and classes in Ruby as the next guy. When I was writing acts_as_readonlyable, I needed to manage multiple connections. I found that the easiest solution for managing active connections was generation of an AR class for each read-only definition and borrowing the connection from it. The usage is acts_as_readonlyable :read_only_entry_in_database_config.
def acts_as_readonlyable(readonly_db)
define_readonly_class(readonly_db) unless ActiveRecord.const_defined?(readonly_class_name(readonly_db))
end

def readonly_class_name(db)
"Generated#{ db.camelize }"
end

def define_readonly_class(db)
ActiveRecord.module_eval %Q!
class #{ readonly_class_name(db) } < Base
self.abstract_class = true
establish_connection configurations[RAILS_ENV]['#{ db }']
end
!

end



Warren Konkel


The ConfigFile class is a quick and easy way to load YAML files located in your Rails application's config directory. Simply place a YAML file into your config directory and then access it like a hash. For example this will read your config/database.yml: ConfigFile['database']['production']['adapter'].
class ConfigFile
def self.[](arg)
@@cached_configs ||= {}
@@cached_config_mtimes ||= {}

base_name = "config/#{arg}.yml"
filename = File.join(RAILS_ROOT, base_name)
raise "ERROR: Config not found: #{base_name}" unless File.exists?(base_name)

if @@cached_configs[arg].nil? || @@cached_config_mtimes[arg] < File.stat(filename).mtime.to_i
@@cached_configs[arg] = YAML.load(File.open(filename))
@@cached_config_mtimes[arg] = File.stat(filename).mtime.to_i
end

@@cached_configs[arg]
end
end