Thursday, February 12, 2009

Some of the First Lessons I learned about being more productive...

1. Get a mac
Seriously... there just isn't a really good excuse not to... I work with ruby... I assume that if you're reading this you work with ruby... if you do not work with ruby this doesn't really apply to you. (why are you reading this?)

I realize that mac isn't cheap... but it's well worth it... can't afford a mac? company won't pay for mac? ... then go linux... cheap hardware and free software... there's just no excuse...

first and foremost... you want your tools to work... the first time... all the time... every minute spent maintaining your tools is minutes you aren't being productive... I'm not saying that you should not maintain your tools... every good craftsman understands the importance of keeping their tools in good working order... but in my experience... it requires far less time to keep my mac purring like a kitten than it ever did my windows machines...

so... do yourself a huge favor... invest in your tools... but remember you don't have to spend a fortune... get the tools that 'just work'... even if they cost more... you'll be happy you did...
2. Use Version Control
You write code without version control?
WHAT?
Do you jump from planes without a parachute?
Coding without with version control is equally retarded...

just say no... and install a version control system... it's free... and it will save your life someday...

Which version control system? Well naturally I'm going to suggest Git... it is the new hotness after all... and after using SVN for a few years... the learning curve for Git is well worth it... just do it... tutorials are free...
3. Commit, and Commit Often and for the love of beer leave a message...
Now you have your development platform, and you have version control. Commit!!!
Commit your work... commit it often... don't be afraid to make micro commits...

Early in my career i was lucky if i committed my work once a day... these days i make alot more... I committed my work more than twenty times today alone...

Why? Why so many commits in a day? Simple...
  1. accountability...
  2. traceability...
  3. portability...
I can look back at my log and see exactly what I did... each commit corresponds to a single task... each log entry tells what that task was... should i decide i want to port functionality from one application to another i can cherry-pick the commits i want to merge between projects.. I simply could not do that with the once daily commits of a couple years ago...

Commit! No change is too small to commit...
4. Don't get bogged down in debates over what is 'best'
Don't try to be the best... that's impossible... instead...
only try to realize the truth...
there is no best...

Best is what works for you... what you are most comfortable with... what allows you to get the job done and done right... and no matter how good it gets... you will eventually always find something better... so don't waste precious time debating with anybody over what is 'best'... always be on the search for what's better...

The Acts As Coder Mission Statement

I kinda figure you're a lot like me..

You spend most of your day at a keyboard banging away at that thing to score your points, maintain your velocity, and keep your boss happy... and somewhere in there you make time to keep up in one or many of your pseudo-social networks... but mostly you do your best to keep your boss happy... After all he's going to have to approve your next time off request... which is right around the corner... so... you work hard...

But seriously... we coders are pretty lazy... now wait... before you get your Utili-kilt in a bunch... maybe lazy isn't the right word... after all i just said we work hard, didn't I?

We work hard... but we are always looking for a way to do our job more efficiently... which means more points in a day... which means higher velocity... which means happier boss... which might just lead to more time off... or more time to spend logged in to your favorite pseudo-social network... or more work done and bigger bonuses... I'll not judge what you do with your spare time...

So...

One of my goals over the last couple years was to find ways to automate as much of my daily drudgery as i could... I mean, really, the core concept of the DRY (Don't Repeat Yourself) paradigm of coding is that you should never have to write the same code twice...

My plan for the foreseeable future is to use this space as my soap box... and share as many of my collection of time-saving, productivity enhancing tips and techniques as i can muster..

Time is money, Time is happiness.. and however you use your spare time... it's always good to have penty of it...

So... stay tuned...

Tuesday, February 3, 2009

link_to with prompt for rails 2.2.2

The feature request said: Create a mechanism whereby a user will be notified when an administrator suspends their account... and further... ensure that the administrator inputs a reason for the suspension. And include that reason in the notification email to the user..

So.. I thought to myself... sure... lets not stop at merely asking the administrator if they are sure about what they're doing when they press that shiny red button that makes the database row magically implode... Lets go a step further and ask the user why they want to press the shiny red candy-like button... that makes the record to vanish in a fiery ball of liquid hot mag-ma.

I thought about this issue for a few moments and decided:

  1. I want this to be as painless as possible to implement (i mean retarded-simple)... i need to be able to do this after a long morning of skulling Irish coffee...
  2. I want to be able to seriously annoy my users and administrators by asking them to explain themselves for every single action they ever do... (not that I would... but I could)
  3. I don't want to have to overload actions or create duplicate actions for every single explainable action in the system... (after all, duplicating work means i have to type that much more... or hit command-c, command-v alot... and how much fun is that... really?)
  4. It would be a huge bonus if this was as easy as link_to :confirm=>'blah blah'
So, in a brief brain dump with my coworkers... somebody (the boss... this is probably why he's the boss)... says in a moment of pure brilliance... use a javascript prompt...

To which i scratched my head... and thought way back to those yonder days of yore... yes, there were alert-style pop-ups that contained text inputs... (that was way-way-back in the days of never-ending q&a sessions with a pre-programmed script... the great-grandfather of being rick-rolled)... i've not seen one of those in a long time... it's crazy... but it just might work...

But wait... Seriously... i figured that somebody else had surely done this already... like maybe the rails core team... surely such basic function already existed... right... I mean, those guys that write this stuff think of everything, don't they?

Seriously... no sarcasm meant in that line... really... nine out of ten times i start doing anything in ruby these days i come to realize that somebody else has already done it... and usually done it far better than i was planning to... so... I scan the API docs, do some serious Googling and eventually scan the source code for link_to... and verify as best i can that nobody has done this yet...

Thinking that nobody has ever done this... This sometimes makes me nervous (like any time i have this feeling... i start to question my motives)... if nobody else has done it... does that mean there is a good reason... has nobody ever needed it... or maybe, like genetic manipulation... maybe it's better that we don't do it... but i think i'm getting a little off track here...

FUH--CUS... EV-A-RAY BODDY MUST FUH-KUS

After much source code tracing and digestion the three simple methods below crafted into a strategically placed barrel-of-monkey-patch will have your rails link_to method capturing that extra explanation string and passing in on through to your controller so you can decide what to do with it... i.e. Email the user whose account just got suspended that they won't be able to log in anymore... or whatever you want... the possibilities are truly limitless.

The beauty is: you get all this using the same conventions you already use.. that is assuming 'you' are my fellow ruby on rails coders and 'you' do things like i do... i know it'a stretch... but ya never know...


link_to 'my Action', action_url, :prompt=>'why do you want to do this?'


This little gem will confront your user with a nifty javascript alert with a string input and will refuse to pass go until the user has entered an excuse for their request. Additional validation on the supplied string should be done server-side and perhaps a flash message and redirect tells the user their excuse wasn't up to snuff..



And i do suppose it's important to mention that the supplied reason will be posted in to your controller action in the form or params[:prompt_reply] ...



Hooray for perpetuating the everlasting nag-screen!!!



And for those of you have been ever-so-patient and read this far i give you... the code... and better yet... forget the code... i mixed this into a simple plugin... snag it from github. http://github.com/bhedana/link_to_with_prompt/




module ActionView
module Helpers
module UrlHelpers

def convert_options_to_javascript!(html_options, url = '')
prompt, confirm, popup = html_options.delete("prompt"), html_options.delete("confirm"), html_options.delete("popup")
method, href = html_options.delete("method"), html_options['href']

html_options["onclick"] = case
when popup && method
raise ActionView::ActionViewError, "You can't use :popup and :method in the same link"
when confirm && popup
"if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;"
when confirm && method
"if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method)} };return false;"
when confirm
"return #{confirm_javascript_function(confirm)};"
when prompt
method ||= :post
"#{prompt_javascript_function(prompt)}"+
"if(prompt_reply) { #{send_prompt_javascript_function(method, url, href)} }; return false;"
when method
"#{method_javascript_function(method, url, href)}return false;"
when popup
"#{popup_javascript_function(popup)} return false;"
else
html_options["onclick"]
end
end

def prompt_javascript_function(prompt)
"var prompt_reply = prompt('#{escape_javascript(prompt)}');"
end

def send_prompt_javascript_function(method, url = '', href = nil)
action = (href && url.size > 0) ? "'#{url}'" : 'this.href'
submit_function =
"var f = document.createElement('form'); f.style.display = 'none'; " +
"this.parentNode.appendChild(f); f.method = 'POST'; f.action = #{action}; "+
"var p = document.createElement('input'); p.setAttribute('type', 'hidden'); p.setAttribute('name', 'prompt_reply'); p.setAttribute('value', prompt_reply); f.appendChild(p);"

unless method == :post
submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); "
submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);"
end

if protect_against_forgery?
submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); "
submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);"
end

submit_function << "f.submit();"
end



end
end
end

Saturday, May 10, 2008

Actionwebservice and rails 2.0

Recently the management of a project of i was working on decided that we should upgrade our application to Rails 2.0. I instantly started to salivate, my mind listing all the fine new features I could finally make use of ( the application had been frozen to 1.2.3 ). So I sallied forth and jumped head first into making the upgrade.

For the most part the upgrade was easy, a handful of deprecated method calls had to be re-factored. No big deal.. The hard part of this upgrade is: The application communicates with mobile devices through XMLRPC. So, we need to maintain actionwebservice.. Sure I’d love to re-factor the whole application to REST but rewriting the Windows Mobile application in the client devices is not an option.



Before i lose you I’ll stop telling the story and jump into the how-to:



First. If you haven’t read the ‘Freezing and Autoloading Gems’ aritcle click ‘back’ and do that first as these steps build on that practice.



Don’t.. that is DO NOT try to unpack a version of actionwebservice gem into your vendor/gems directory I tried several different versions and none of them worked.. complaints about missing methods and such..



Do however checkout actionwebservice from it’s svn trunk




cd vendor/gems/
svn co http://svn.rubyonrails.org/rails/ousted/actionwebservice/ actionwebservice


once actionwebservice is installed add to your environment or an initializer.




require 'actionwebservice'


At first glance you might think you’re done. but i seems to have to add one more tweak to get things working for me. I needed to add my web service API definition to my load path. so i went back to environment.rb and added the following.




config.load_paths += %W( #{RAILS_ROOT}/app/apis )


Finally, to ensure that your tests will run (you are testing your api, right?) open your test_helper.rb or your spec_helper.rb and add the following line




require 'action_web_service/test_invoke'


And that allows your legacy web service API to ride modern rails..

Monday, May 5, 2008

Freezing and Autoloading Gems - Not just for Rails

Now this practice in part is counterintuitive to the beauty of ruby gems. After all, the DRY concept of gems means removing code from your application. Especially that code that is shared between multiple applications on the same server. Gems are easy to intstall, easy to share, and easy to maintain.



But sometimes you want to reduce the number of steps required to deploy your application to a new server or perhaps your application required a one time customization to a gem library or maybe for whatever reason you want to keep all code dependencies for your application in one tree.



There is a straightforward way to make this happen.



Create a place in your application tree to store the gems your app uses. I chose to create a vendor/gems/ directory. So create the directory and issue the commands below




cd vendor/gems/
unpack gemName


Now these gems are part of our application source tree but aren’t yet visible to our application environment. We need to add these gems load paths to our application load path. Open config/environment.rb and add the following code (place it inside the Rails::Initializer.run do |config| code block):




config.load_paths += Dir["#{RAILS_ROOT}/vendor/gems/**"].map do |dir|
File.directory?(lib = "#{dir}/lib") ? lib : dir
end


With this done.. you can go about your business and use gem ‘genName’ as you typically do, however, I like the sledgehammer approach.. it’s fun.. and i want to be lazy and have all the gems in my vendor/gems directory loaded auto-magically. Add the following code to your environment.rb or one of your initializers if you’re running Rails 2..




Dir[File.dirname(__FILE__) + "/../vendor/*"].each do |path|
gem_name = File.basename(path.gsub(/-\d+.\d+.\d+$/, ''))
gem_path = path + "/lib/" + gem_name + ".rb"
require gem_path if File.exists? gem_path
end


With this you can freeze any gem into your application and have that gem automatically load.

Saturday, May 3, 2008

Rails Migrations - Directly Import SQL

Recently a project i was working on required to integration of triggers and stored procedures. To my knowledge rails migrations do not have to ability to create and manage stored procedures. And why would it really? Stored Procedures and Triggers are database specific and not all Database engines support them.

Now, you can execute database specific queries directly through the connection like this:




ActiveRecord::Base.connection().execute( "call #{some custom query};" )


and in many instances this may be all you need.



However an issue (bug?) in ActiveRecord means that ActiveRecord does not understand the syntax used to set the delimiter.. a requirement for creating stored procedures and triggers.



In an effort to work around ActiveRecord limitations and still stay as DRY as possible by managing the application schema through migrations I created a monkey patch to the ActiveRecord MySQL connection adapter to load the sql commands directly to MySQL



It’s super simple.. here’s how..



Add the following code to your environment, initializers, or separately in the lib folder. If you take the lib folder approach don’t forget to require the file..




class ActiveRecord::ConnectionAdapters::MysqlAdapter
def import_sql(file)
conf = ActiveRecord::Base.configurations[RAILS_ENV]
sql_file = File.join(File.join(File.dirname(__FILE__), "sql" ), "#{file}.sql")
cmd_line = "mysql -h "+conf["host"]+" -D "+conf["database"]+ " --user="+conf["username"]+" --password="+conf["password"]+" < "+sql_file raise Exception, "Error executing " + cmd_line unless system(cmd_line)
end
end


Then.. create your sql commands.. i chose to store these commands in the db/ directory in a new folder called sql/


Create one file per command.. That is, one file to create your trigger and one file to remove your trigger.


I leave the practice of creating the actual sql syntax to you..


Then.. create your sql commands.. i chose to store these commands in the db/ directory in a new folder called sql/


Create one file per command.. That is, one file to create your trigger and one file to remove your trigger.


I leave the practice of creating the actual sql syntax to you..And this is a sample migration that used our new sql importing mechanism.




class AddTriggers < ActiveRecord::Migration
def self.triggers
%w( insert update )
end
def self.up
triggers.each do |trigger|
import_sql("t_#{trigger}_up.sql")
end
end
def self.down
triggers.each do |trigger|
import_sql("t_#{trigger}_down.sql")
end
end
end

Friday, December 14, 2007

Acts as Taggable on Steroids - the missing muscle

Recently i decided to use Acts as Taggable on Steriods rather than my old favorite, It’s non ‘roided cousin. AATOS is a nice alternative in my opinion because of it’s polymorphic STI taggings. It makes my database a little DRY-er and DRY is always good. Well, in terms of code, anyway.

But nothing worthwhile is without a little struggle and quickly the undeveloped muscle of AATOS was blindingly apparent.

My flash tag cloud browser, relies heavily on the ability to query for related tags. A method that the sterioded version of taggable was missing.

Undaunted, i sent Mr Steriod to the gym for a little training, and now his undeveloped muscle is bulging.


Add the little patch below and Mr Steriod will be squat-thrusting related tags in a jiffy.





module ActiveRecord
module Acts
module Taggable
module SingletonMethods

def find_related_tags(list, options={})
tags = escape_tags(list).join(',')
return [] if tags.blank?
related = find_tagged_with(list)
return [] if related.blank?
related_ids = related.map(& :id).map(& :to_s).join(', ')
Tag.find :all, options.merge({
:select => 'tags.*, COUNT(tags.id) AS count',
:from => 'tags',
:joins => "JOIN taggings ON taggings.taggable_type = '#{base_class.name}'
AND taggings.taggable_id IN (#{related_ids})
AND taggings.tag_id = tags.id",
:order => options[:order] || 'count DESC, tags.name',
:group => "tags.id, tags.name HAVING count > 0 AND tags.name NOT IN (#{tags})"
})
end

protected

def escape_tags(list)
list.map { |t| t.to_s.strip.downcase }.
reject { |t| t.blank? }.
uniq.
map { |t| "'#{connection.quote_string(t)}'" }
end

end
end
end
end