<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-19901248</atom:id><lastBuildDate>Wed, 08 Feb 2012 14:58:09 +0000</lastBuildDate><category>space</category><category>ruby</category><category>viruses</category><category>Sears</category><category>media</category><category>technology</category><category>marathon</category><category>solution</category><category>front loader</category><category>aasm</category><category>news</category><category>DIY</category><category>development</category><category>customer</category><category>community</category><category>aging</category><category>corporate</category><category>washer</category><category>expectations</category><category>SEM</category><category>society</category><category>printer</category><category>computer</category><category>repair</category><category>physics</category><category>code</category><category>review</category><category>hardware</category><category>science</category><category>DAO</category><category>humor</category><category>overview</category><category>exercise</category><category>business</category><category>start up</category><category>advice</category><category>process</category><category>politics</category><category>success</category><category>economy</category><category>thanks</category><category>blog</category><category>rspec</category><category>ruby on rails</category><category>product management</category><category>SEO</category><category>wisdom</category><category>opinion</category><category>wood</category><category>software</category><category>hard drive</category><category>search</category><category>posts</category><category>Getting Real</category><title>Darn Practical by Degen-Portnoy</title><description>Essays and postings on Software and Technology Leadership from a veteran software development leader and entrepreneur</description><link>http://degenportnoy.blogspot.com/</link><managingEditor>noreply@blogger.com (Peter Degen-Portnoy)</managingEditor><generator>Blogger</generator><openSearch:totalResults>75</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MondayByDegenPortnoy" /><feedburner:info uri="mondaybydegenportnoy" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>MondayByDegenPortnoy</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-795868866148756527</guid><pubDate>Wed, 04 Jan 2012 13:33:00 +0000</pubDate><atom:updated>2012-01-04T08:33:02.067-05:00</atom:updated><title>Nice Step Forward for VirtualBox</title><description>I just downloaded version 4.1.8 of Oracles VirtualBox Manager and was delighted to see that it offered to download the extension pack and install it for me.&amp;nbsp; That was always a bothersome additional step that needed to be done and bringing that into VirtualBox improves the usability of the product.&amp;nbsp; Also, this encourages me to stay more current with updates, since the update process involves "manually" downloading and installing one file instead of two.&amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
Nice improvement and an "Attaboy" to the VirtualBox developers!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-795868866148756527?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/8eCfGj2R_u4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/8eCfGj2R_u4/nice-step-forward-for-virtualbox.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2012/01/nice-step-forward-for-virtualbox.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-1063709028270146331</guid><pubDate>Tue, 13 Dec 2011 16:14:00 +0000</pubDate><atom:updated>2011-12-13T11:14:44.445-05:00</atom:updated><title>Predicting Corporate Failure</title><description>Bob Lewis of IT Catalysts has a compelling essay in which he predicts the failure of a company, &lt;a href="http://www.weblog.keepthejointrunning.com/?p=4465"&gt;Business failure in progress&lt;/a&gt;.&amp;nbsp; Worth a read.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-1063709028270146331?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/_Akw37-Eeic" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/_Akw37-Eeic/predicting-corporate-failure.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/12/predicting-corporate-failure.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-723356741255030026</guid><pubDate>Wed, 07 Dec 2011 19:55:00 +0000</pubDate><atom:updated>2011-12-07T15:19:47.175-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">advice</category><category domain="http://www.blogger.com/atom/ns#">business</category><title>Don't Go There</title><description>A few years ago, I worked for a company that had a pool table.  It was cool and different.  A lot of edgy companies had Foosball tables and Ping Pong tables, but a pool table is a different beast altogether.  This baby had three or four huge slabs of slate over an inch thick apiece that were laid out on a bed of stuff -- mud, clay, something -- and carefully leveled over the better part of an entire day.  Then the stuff was left to set over night before the felt was applied.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We played pool to ease tension, introduce new employees to the company and, finally, to determine who was the "best".  That is, we started a ladder.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As we played, we realized that we regularly getting ourselves into situations that were just tough to work out of.  We didn't know what to do.  Sometimes we tried to force our way through, sometimes we tried to finesse our way out.  Usually, our efforts were too little and too late and our opponent trounced us.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So we got training.  We brought in an instructor.  A Pool Shark.  The movies had nothing on this guy.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;He wowed us and explained many aspects and strategies.  At the end of his session, the inevitable question came up; "What do you do when you find yourself in a situation like this?"  Then we would layout some of the most challenging plays in which we found ourselves.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;He looked at the table and the balls laid out on it and a pained expression crossed his face.  "I wouldn't let myself get into this situation," was his reply.  "Never."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;He knew enough about the game to know where the danger areas lay.  He had played and practiced enough to know how to keep is game in the area where he can control it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This story occurred to me as my colleagues and I struggle to stand up a large and complicated release that was pushed into production too soon.  We know better.  We know where the danger areas lie and how to avoid them.  But we were pushed right onto them.  A mandate was given and we did our best to march to it.  Sometimes you just have to do that.  But if and when you do, it is helpful to remember that you chose to ignore the evidence that it probably wouldn't work smoothly.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Just don't go there.  Don't set things that aren't highly likely to succeed, especially when lots of dollars are on the line.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-723356741255030026?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/Cfi112_JBy4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/Cfi112_JBy4/dont-go-there.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/12/dont-go-there.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-8013475173876508108</guid><pubDate>Sun, 04 Dec 2011 17:34:00 +0000</pubDate><atom:updated>2011-12-04T12:38:18.097-05:00</atom:updated><title>Combine Wolfram Alpha and Siri</title><description>Siri is seriously cool (c'mon, have you told your iPhone you love it?).&lt;br /&gt;&lt;br /&gt;Wolfram Alpha is seriously cool.&lt;br /&gt;&lt;br /&gt;Here are some fun hints on how to combine them: &lt;a href="http://www.tuaw.com/2011/10/28/10-cool-things-you-can-do-with-wolfram-alpha-and-siri/"&gt;http://www.tuaw.com/2011/10/28/10-cool-things-you-can-do-with-wolfram-alpha-and-siri/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;How about this:  Say to Siri, "Ask Wolfram what flights are overhead" to find out which jet contrails are over head.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-8013475173876508108?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/3jAHYgi5H1I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/3jAHYgi5H1I/combine-wolfram-alpha-and-siri.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/12/combine-wolfram-alpha-and-siri.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-3986973326515316161</guid><pubDate>Wed, 12 Oct 2011 20:20:00 +0000</pubDate><atom:updated>2011-10-12T16:52:30.156-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">humor</category><category domain="http://www.blogger.com/atom/ns#">expectations</category><category domain="http://www.blogger.com/atom/ns#">business</category><title>The Perfect Engineer</title><description>For reasons that should be shortly entirely obvious, I have been thinking about job interviews.  It was so bad that instead of typing "routes.rb" while looking for a file, I typed "resume.rb".  Heh.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And, in thinking about this I realized what I think companies want out of the perfect engineering candidate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We've had a good deal of changes where I work.  Let me state right now that I have a tremendous amount of confidence in the leadership, their vision and the work that we're doing.  However, when things change, folks get all shook up.  First, after a sizable push to get new infrastructure up and running on an accelerated schedule, we lost a bunch of folks.  Some were contractors that wrapped up and others were stalwart members who accomplished something really great and felt it was time to move on to new challenges.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then, we had a change in team leadership. This caused more unrest and another flurry of departures.  Although we're looking for replacements, they are hard to come by and a linear extrapolation of our head count over the past year shows no one left by next July.  We mostly look at that downward progression as gallows humor.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, thinking about my departing colleagues and having had to do due diligence myself, it occurred to me that companies seem to be looking for an engineer with the following qualifications:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Amazing Abstract Thinker&lt;/b&gt;: Software architecture, design and algorithms&lt;/li&gt;&lt;li&gt;&lt;b&gt;Rock-Solid Concrete Contributor&lt;/b&gt;: Code structure, comments, testing, source code control, branches, merging. Master of multiple languages&lt;/li&gt;&lt;li&gt;&lt;b&gt;Top-Notch Manger of the User Experience&lt;/b&gt;: Site flow design, UI design, HTML, CSS, JavaScript implementation&lt;/li&gt;&lt;li&gt;&lt;b&gt;Unshakable Foundation Provider&lt;/b&gt;: Schema architecture, database configuration, SQL wizard across multiple databases both commercial and open source&lt;/li&gt;&lt;li&gt;&lt;b&gt;Deployment Master&lt;/b&gt;: development, staging and production system configuration and management, deployment processes and scripts&lt;/li&gt;&lt;li&gt;&lt;b&gt;Systems Genius&lt;/b&gt;: Unix, OS/X, Windows, Networks and OS internals&lt;/li&gt;&lt;li&gt;&lt;b&gt;Unparalleled Business Analyst&lt;/b&gt;: Business needs analysis, specifications, requirements documentation, feature prioritization, cost estimation, ROI projections&lt;/li&gt;&lt;li&gt;&lt;b&gt;Zen Guru&lt;/b&gt;: personable, calm, professional, communicative, approachable, polite and respectful, unflappable&lt;/li&gt;&lt;li&gt;&lt;b&gt;Project Management Prodigy&lt;/b&gt;: team management, task estimation, assignment, prioritization, budgeting, conflict resolution, risk management&lt;/li&gt;&lt;li&gt;&lt;b&gt;Strategic Wonder&lt;/b&gt;: project current business realities into future business needs and align technical infrastructure, staff and supporting resources to meet tomorrows needs today.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Workaholic&lt;/b&gt;: Put in a solid 40 hour week plus full time availability for emergencies and fire-fighting&lt;/li&gt;&lt;li&gt;&lt;b&gt;Hero&lt;/b&gt;: Take critical business needs and urgent projects, pull out all the stops and deliver them ahead of all expectations&lt;/li&gt;&lt;li&gt;&lt;b&gt;Inexpensive&lt;/b&gt;: after all, we're just talking about friggin' writing code for a web site.  How friggin' hard can that possibly be?  Plus, there are a ton of engineers and they're easy to please.  Give 'em a fast computer and lots of free food and they're fine.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Ja, this is pretty snarky.  But as I review it, I'm gonna stick by it.  I recently realized that I started managing folks when I was 16 and ran a ballet studio for the summer while the owners were traveling out of the country.  I've been doing this management stuff for over 30 years.  Holy cow!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;BTW, I can lay legitimate and concrete claim to most all of the aspects identified above and feel darn good about that.  However, I've worked with a lot of folks and know that really good engineers are really hard to find; may be 1 out of 20.  They have the ability to sustain an entire company and turn it around on a dime as needed.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Like I said, I feel good about where I am.  I know the value I bring and know that I continue to work with some very talented engineers whom I respect tremendously.  I also know that I would be hard pressed to replace them and hope I don't have to any time soon.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-3986973326515316161?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/iRCYaEl6OFw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/iRCYaEl6OFw/perfect-engineer.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/10/perfect-engineer.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-5408699707882454093</guid><pubDate>Fri, 20 May 2011 01:24:00 +0000</pubDate><atom:updated>2011-12-27T20:10:00.466-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">customer</category><category domain="http://www.blogger.com/atom/ns#">review</category><category domain="http://www.blogger.com/atom/ns#">business</category><title>Customer Relationship Failures</title><description>Here are a few instances of where companies are failing to meet my expectations.  For each company and product, I am actively looking for acceptable alternatives.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Bank of America&lt;/span&gt;: I just downloaded my recent activity.  I had been royally annoyed that BofA signed me up for paperless statements and then claimed that I had requested that. Never.  I rely on the monthly statement to remind me to reconcile and I like the security of holding onto paper records for this purpose.&lt;br /&gt;
&lt;br /&gt;
So, I logged on and searched and searched and searched until I found where I turn OFF paperless statements.&lt;br /&gt;
&lt;br /&gt;
Imagine my surprise when I saw monthly maintenance fees on all my checking accounts.&lt;br /&gt;
&lt;br /&gt;
A new payment schedule now declares that because I am not a eBanking customer, because I get a paper statement, they are charging me nearly $30 in monthly fees.  And, I couldn't even call them at 9:20 pm to ask about it, because their customer service centers were closed.&lt;br /&gt;
&lt;br /&gt;
I hate surprises from Bank of America.  Bank of America; you suck.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Verizon Wireless:&lt;/span&gt; I hate my phone.  It's an HTC Droid Eris and its just underpowered, weak and pathetic.  As a software engineer, I hate using it, especially since I did some iPhone development and had an iPhone for a while. But phones apart, I hate Verizon Wireless more.&lt;br /&gt;
&lt;br /&gt;
At one point a few years ago, while doing iPhone development, I was also helping get a start up off the ground (shout out to &lt;a href="http://www.starstreetsports.com/"&gt;Star Street Sports&lt;/a&gt;!) and my wife and I blew away our minutes.  Me on AT&amp;amp;T and her on Verizon.  We had over $1000 in additional fees.&lt;br /&gt;
&lt;br /&gt;
I called AT&amp;amp;T.  They asked if I would upgrade to the unlimited minutes plan (only $20 more per month) and, if so, they would waive all the overage fees.  I agreed in a heartbeat.&lt;br /&gt;
&lt;br /&gt;
I called Verizon.  They asked if I would upgrade to the unlimited minutes plan (only $20 more per month) and, if so, they would -- are you ready? -- give me a 30% discount.  What?  Excuse me?  Your competition waived all the fees and left me feeling really great.  You gave me a sucky deal and I had already been a customer for over 14 years, plus added four more additional lines.&lt;br /&gt;
&lt;br /&gt;
Then I discovered that they have a policy that they won't discount more than 50%.  So why did I only get 30%?  I called back.  You see, it's up to the representative who takes the call.  So, for what ever reason -- I'm a jerk, the rep was having a bad day -- I got 30% off of the egregious over charges instead of 50%.  And I'm still seething because they didn't give me nearly as good a deal as AT&amp;amp;T.&lt;br /&gt;
&lt;br /&gt;
Verizon Wireless; you suck, too.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Callpod Keeper&lt;/span&gt;:  I used to like my Callpod Keeper.  I found it while using an iPhone.  Callpod offered a free mobile password safe and I needed a replacement for my old one, which was open sourced and no longer being maintained.  For $30 I could buy the desktop and then sync between mobil and desktop.  Sweet!&lt;br /&gt;
&lt;br /&gt;
When I switched to my sucky HTC Droid Eris (seriously, this phone is crap), I found Callpod has an Android version, which I installed.&lt;br /&gt;
&lt;br /&gt;
Not long thereafter, having upgraded the app, the app kept asking if I wanted to try a 30 day trial of their premium service, wherein I could sync to the cloud instead of my own desktop.  No.  No, I don't.&lt;br /&gt;
&lt;br /&gt;
Finally the friggin' pop-ups stop and I get around to syncing my devices.  But I can't.  Because now, without telling me, Callpod changed the rules.  Now, I &lt;span style="font-weight: bold;"&gt;have&lt;/span&gt; to upgrade to their premium service to sync &lt;span style="font-weight: bold;"&gt;at all&lt;/span&gt;.  They hid this change -- it was never mentioned anywhere I could see in the upgrade summaries.  Now I can't sync my mobile password safe with my desktop safe and the two have inevitably drifted apart.&lt;br /&gt;
&lt;br /&gt;
Callpod: you suck too.  I'm chucking your ass out on the street as soon as I find another password safe.&lt;br /&gt;
&lt;br /&gt;
So, there you go.  Three examples of different companies pissing me off so royally that I actually spent my time to complain about it publicly.&lt;br /&gt;
&lt;br /&gt;
This is why it was so important to me to make my Hold-it! Game Card Organizer an outstanding value.  First, it is great to use and really helps make dozens of games play faster and better.  Second, it is seriously sturdy -- I had a 400 lbs. fellow stand on one at a game convention without damaging the unit at all.  Finally, I offer an unconditional -- yes, without any conditions -- guarantee for your money back if you don't like my product.  Return it for your purchase price.&lt;br /&gt;
&lt;br /&gt;
OK, so the Hold-it! hasn't made me wealthy and it really sucked that the hobby-game industry was deflating at the time I was trying to get my product into the marketplace, but it taught me tons about how to make something that customer will value.&lt;br /&gt;
&lt;br /&gt;
I do no marketing or advertising at all.  Nothing.  And the Hold-it! continues to sell from my old, ugly &lt;a href="http://www.innovatiuminc.com/"&gt;website&lt;/a&gt; all on its own.  Word of mouth.  Because the folks who have purchased it (and I've sold it to nearly every continent on the earth) know they have a really good product.&lt;br /&gt;
&lt;br /&gt;
If I could do it, then I really expect Bank of America, Verizon Wireless and Callpod to figure out that pissing off the customer is not good business.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-5408699707882454093?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/O56_xLv8LJA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/O56_xLv8LJA/customer-relationship-failures.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/05/customer-relationship-failures.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-3638592193683119256</guid><pubDate>Wed, 04 May 2011 14:50:00 +0000</pubDate><atom:updated>2011-05-04T11:08:39.819-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">review</category><category domain="http://www.blogger.com/atom/ns#">business</category><title>Join.me is a winner</title><description>We have a contractor who works remotely and I was chatting with him on the phone about the project to which we are both assigned.  I was trying to talk him through some of the specifics of our administration tool when he said that this would be a lot easier if he could just see my screen.&lt;br /&gt;&lt;br /&gt;First thought was iChat, but I already had Colloquy and Adium running and last time I tried iChat it wouldn't connect to the AIM server.  &lt;sigh&gt; (I've since fixed that by connecting to the AIM server on port 443).&lt;br /&gt;&lt;br /&gt;Next, I remembered getting an email from &lt;a href="http://www.logmein.com"&gt;LogMeIn&lt;/a&gt; about a new service for free screen sharing.  I went to the LogMeIn site and found &lt;a href="http://join.me"&gt;Join.me&lt;/a&gt; and clicked on it.  It started up Java, and I downloaded some Java code and a small tool bar appeared at the top of my screen.  It didn't seem to take even a minute.  I pasted the link provided in the tool bar into my Colloquy chat window and my colleague clicked on it.&lt;br /&gt;&lt;br /&gt;He didn't need to down load anything.  The Java code runs on my system, pushes my screen data to the server and he got a Flash driven experience, complete with zooming and screen resizing right away.  We never had any lag, though he was working from home quite a few states away.&lt;br /&gt;&lt;br /&gt;Fast, Easy, Free, Unobtrusive, Highly Functional: Join.me is a winner&lt;br /&gt;&lt;/sigh&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-3638592193683119256?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/vZUaE_n0Cog" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/vZUaE_n0Cog/joinme-is-winner.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/05/joinme-is-winner.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-1067482418956520462</guid><pubDate>Tue, 25 Jan 2011 14:30:00 +0000</pubDate><atom:updated>2011-01-25T09:36:58.251-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">humor</category><title>Deja Rue - I know again that I will regret this</title><description>Chatting with a colleague about parenting.  He says, "You know how you're always talking about how much you like your kids?  Well, I've gotten to that point!"  "Oh," says another colleague, "your kids are finally interesting?" "Yes, " responds the first, "they're old enough to be interesting now.  My wife and I aren't talking about orphanages so much any more."&lt;br /&gt;&lt;br /&gt;I chime in, "I think you're up to at least 150, maybe 200."&lt;br /&gt;&lt;br /&gt;My colleague is puzzled and it appears on his face.&lt;br /&gt;&lt;br /&gt;"Thousand dollars in psychotherapy bills to help your kids recover" I clarify.&lt;br /&gt;&lt;br /&gt;Comprehension dawns on the first as the second says, "Oh, sure, as in 'I just ruined the kid for month with that!'"&lt;br /&gt;&lt;br /&gt;"Yes, " I agree, "we call that 'deja rue', as in 'Once again, I know that I'll regret this.'"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-1067482418956520462?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/qGj96n3Yiic" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/qGj96n3Yiic/deja-rue-i-know-again-that-i-will.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/01/deja-rue-i-know-again-that-i-will.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-7132913700468637981</guid><pubDate>Fri, 07 Jan 2011 16:42:00 +0000</pubDate><atom:updated>2011-01-07T11:46:11.309-05:00</atom:updated><title>Engineering Prioritization</title><description>Welcome to the Engineering Department.&lt;br /&gt;&lt;br /&gt;So we can respond to your request, please let us know the priority of the request:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;High&lt;/li&gt;&lt;li&gt;Higher&lt;/li&gt;&lt;li&gt;Urgently High&lt;/li&gt;&lt;li&gt;Wicked Urgently High&lt;/li&gt;&lt;li&gt;Higher Than That&lt;/li&gt;&lt;li&gt;Critically Wickedly Urgently Higher&lt;/li&gt;&lt;li&gt;I'm the CEO&lt;/li&gt;&lt;/ul&gt;Thank you&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-7132913700468637981?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/9DLHkPsguNw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/9DLHkPsguNw/engineering-prioritization.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/01/engineering-prioritization.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-7019290263070267970</guid><pubDate>Wed, 05 Jan 2011 20:55:00 +0000</pubDate><atom:updated>2011-12-09T07:37:59.076-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">development</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>Bundler Install issue with Nokigiri on OS/X</title><description>I finally have an opportunity to move into the Ruby 1.9.2 and Rails 3.0 world having spent some time in earlier versions while supporting our main applications.  Let's note that I know some other folks who are in a similar situation, which may have been predicated by our moving from OS/X 10.5 Leopard to 10.6 Snow Leopard by using the automatic migration rather than by manually re-installing all of our libraries, tools and applications. I had to do some rebuilding and patching just to get my Snow Leopard system up and running.  However, this may be an hold-over from that process.&lt;br /&gt;
&lt;br /&gt;
I used RVM to keep my Ruby 1.8.6 and 1.9.2 versions playing nicely.  After installing Ruby 1.9.2 (wicked easy), I downloaded Rails 3.0.3, got the code base and ran 'bundler install' to install all the needed gems.&lt;br /&gt;
&lt;br /&gt;
The process failed while building nokogiri.  The error was:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 85%;"&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;libiconv is missing.  please visit http://nokogiri.org/tutorials/installing_nokogiri.html for help with installing dependencies.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Popping over to the supplied URL showed that I probably needed the libxml2 and libxslt libraries.  I didn't think so because I was sure nokogiri was working in my other ruby environment, but nonetheless I ran:&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;sudo port install libxml2 libxsl&lt;/code&gt;&lt;/pre&gt;
After doing so, I tried the &lt;span style="font-size: 85%; font-weight: bold;"&gt;&lt;span style="font-family: courier new;"&gt;bundle install&lt;/span&gt;&lt;/span&gt; again only to have the same error.&lt;br /&gt;
&lt;br /&gt;
Now I was looking at a crisis.  One colleague who has successfully navigated this waterway recommended that I rely on &lt;span style="font-size: 85%; font-weight: bold;"&gt;&lt;span style="font-family: courier new;"&gt;homebrew&lt;/span&gt;&lt;/span&gt; for package management.  However, I've used &lt;span style="font-size: 85%; font-weight: bold;"&gt;&lt;span style="font-family: courier new;"&gt;port&lt;/span&gt;&lt;/span&gt; and &lt;span style="font-family: courier new; font-size: 85%; font-weight: bold;"&gt;fink&lt;/span&gt;, plus &lt;span style="font-size: 85%;"&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;homebrew&lt;/span&gt;&lt;/span&gt; doesn't link to system directories by default, so I knew there would be some pain.  I briefly considered uninstalling port and moving entirely to &lt;span style="font-family: courier new; font-size: 85%; font-weight: bold;"&gt;homebrew&lt;/span&gt;, but I have nearly 200 installed packages.  Didn't want to go there.&lt;br /&gt;
&lt;br /&gt;
Simultaneously, I was working in another terminal when I realized that my subversion was no longer working.  It was complaining about a newly installed &lt;span style="font-family: courier new; font-size: 85%; font-weight: bold;"&gt;libiconv&lt;/span&gt;, which was installed with the &lt;span style="font-family: courier new; font-size: 85%; font-weight: bold;"&gt;libxml2&lt;/span&gt;.  This actually was a good thing.&lt;br /&gt;
&lt;br /&gt;
Now cutting to the chase:  The Berekly DB needed to be updated in order to make all these things work.  So I uninstalled Berekly DB, which involved uninstalling apr-util, python26, subversion, serf, and gone-doc-utils (using port for all of this).  Then I did a '&lt;span style="font-size: 85%; font-weight: bold;"&gt;&lt;span style="font-family: courier new;"&gt;port clean &lt;package&gt;&lt;/package&gt;&lt;/span&gt;&lt;/span&gt;' on all those packages and reinstalled everything.&lt;br /&gt;
&lt;br /&gt;
Subversion now worked, but the bundle install still failed.  Confident that the problem lay elsewhere, I cast around and found Chris Roos' post on &lt;a href="http://chrisroos.co.uk/blog/2010-03-26-libxml2-problems-when-installing-nokogiri"&gt;Libxml2 Problems when Installing Nokogiri&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The solution I chose was to do a universal install of the libxml and libxlst libraries with&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="code shell"&gt;  $ sudo port upgrade --enforce-variants libxml2 +universal
 $ sudo port upgrade libxslt +universal&lt;/pre&gt;
The &lt;span style="font-size: 85%; font-weight: bold;"&gt;&lt;span style="font-family: courier new;"&gt;bundle install&lt;/span&gt;&lt;/span&gt; worked after this, Subversion still works and I'm back in business.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-7019290263070267970?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/EcyeEXoEqgs" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/EcyeEXoEqgs/bundler-install-issue-with-nokigiri-on.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2011/01/bundler-install-issue-with-nokigiri-on.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-8730687330902755878</guid><pubDate>Tue, 28 Dec 2010 20:36:00 +0000</pubDate><atom:updated>2010-12-28T15:43:05.568-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">customer</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">humor</category><title>Things not to say to the customer</title><description>Yes, I know this is irreverent, but I'm a bit punch happy, so here are some ideas about things that one should not say to the customer.  Especially one who has been pretty good about getting slow support.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;After banging on this product for over a year, we’ve moved on emotionally, spiritually and strategically.  The product is going to phased out soon and we’re really busily focused on doing things that generate a whomp-load more revenue right now.  So, for right now, we’re just plugging our ears with coffee grinds and ignoring the problem&lt;/li&gt;&lt;li&gt; My apologies for the delay.  My mom says I shouldn’t talk to you.&lt;/li&gt;&lt;li&gt;Thanks for following up on this.  Unfortunately the work to dig into the product issues has temporarily been put on an indefinite hold.&lt;/li&gt;&lt;li&gt;My apologies but a traumatic brain injury has wiped out all my memories and knowledge of who you are and what you do.  Could we start over?&lt;/li&gt;&lt;/ul&gt;Clearly, someone in Sales needs to pick up the phone.  Hello, Sales?  Um, Sales?&lt;br /&gt;&lt;br /&gt;Ah.  They're out, erm, networking.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-8730687330902755878?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/kgXc7VTtL88" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/kgXc7VTtL88/things-not-to-say-to-customer.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2010/12/things-not-to-say-to-customer.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-1103789426766848179</guid><pubDate>Thu, 20 May 2010 15:25:00 +0000</pubDate><atom:updated>2011-12-09T07:17:41.324-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ruby</category><category domain="http://www.blogger.com/atom/ns#">development</category><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>Rails alias_method_chain explained with pictures!</title><description>I've been meaning to do this for a while because I keep coming across alias_method and alias_method_chain in Rails code.  I understood what was going on, but felt that I never grokked it.  So, I finally mapped out what happens, drew some pictures, and, voila! Enlightenment!&lt;br /&gt;
&lt;br /&gt;
Since I firmly believe that the best way to learn something is to teach it, I thought I would document what I learned in the hopes that it will be beneficial to someone else and firmly cement my understanding.  So without further ado:&lt;br /&gt;
&lt;br /&gt;
It is important to keep in mind that a method name is essentially a constant symbol and points to a block of code. "alias_method" is a Ruby class Module method with the signature:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;alias_method(new_name, old_name)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And, "alias_method_chain" looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;alias_method_chain :method_name, :feature&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
That's the easy part.&lt;br /&gt;
&lt;br /&gt;
For the purpose of this example, I'm examining the behavior of:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;alias_method_chain :render, :feature&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The &lt;span style="font-family: courier new; font-weight: bold;"&gt;alias_method&lt;/span&gt; method makes a copy of the method block and assigns the new_name constant to point to the copy of the method block.  So, it looks something like this:&lt;br /&gt;
&lt;br /&gt;
Here's the method &lt;span style="font-family: courier new; font-weight: bold;"&gt;render&lt;/span&gt; and its method block:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://4.bp.blogspot.com/__7xcUyenJzo/S_VWJNBEoTI/AAAAAAAAACA/ylZ8ezzcDgc/s1600/alias_method_img_1.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5473375638251675954" src="http://4.bp.blogspot.com/__7xcUyenJzo/S_VWJNBEoTI/AAAAAAAAACA/ylZ8ezzcDgc/s320/alias_method_img_1.png" style="cursor: pointer; display: block; height: 106px; margin: 0px auto 10px; text-align: center; width: 143px;" /&gt;&lt;/a&gt;&lt;br /&gt;
After we call &lt;span style="font-family: courier new; font-weight: bold;"&gt;alias_method :render_without_feature, :render&lt;/span&gt; we have the following:&lt;br /&gt;
&lt;a href="http://4.bp.blogspot.com/__7xcUyenJzo/S_VWkj_mR0I/AAAAAAAAACI/11l-CPzIZhs/s1600/alias_method_img_2.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5473376108275976002" src="http://4.bp.blogspot.com/__7xcUyenJzo/S_VWkj_mR0I/AAAAAAAAACI/11l-CPzIZhs/s320/alias_method_img_2.png" style="cursor: pointer; display: block; height: 192px; margin: 0px auto 10px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;At this point, if we wanted to, we could redefine the &lt;span style="font-family: courier new; font-weight: bold;"&gt;render&lt;/span&gt; method, which would replace the original {render} block with new functionality.  And, as it is often explained, the original functionality is still available at the &lt;span style="font-family: courier new; font-weight: bold;"&gt;render_without_feature&lt;/span&gt; method.&lt;br /&gt;
&lt;br /&gt;
However, as it is often explained, what is desired in Rails library code is to redefine an existing method while saving the original functionality under a new name.  Therefore, what we see in Rails code was often:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;alias_method :render_with_feature, :render&lt;/span&gt; &lt;span style="font-family: courier new;"&gt;&lt;br /&gt;alias_method :render, :render_with_feature&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
We already looked at the first line.  Let's look at the second line.&lt;br /&gt;
&lt;br /&gt;
The second line is assigning the constant "render" to a copy of the "render_with_feature" functionality.  It looks like this:&lt;br /&gt;
&lt;a href="http://1.bp.blogspot.com/__7xcUyenJzo/S_VZllgzbNI/AAAAAAAAACQ/i8YFrQq-3RM/s1600/alias_method_img_3.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5473379424398437586" src="http://1.bp.blogspot.com/__7xcUyenJzo/S_VZllgzbNI/AAAAAAAAACQ/i8YFrQq-3RM/s320/alias_method_img_3.png" style="cursor: pointer; display: block; height: 320px; margin: 0px auto 10px; text-align: center; width: 177px;" /&gt;&lt;/a&gt;Now, &lt;span style="font-family: courier new; font-weight: bold;"&gt;render&lt;/span&gt; will call the code block with the new feature and &lt;span style="font-family: courier new; font-weight: bold;"&gt;render_without_feature&lt;/span&gt; will call the original render block.&lt;br /&gt;
&lt;br /&gt;
This is the key to the entire Rails helper, &lt;span style="font-family: courier new; font-weight: bold;"&gt;alias_method_chain&lt;/span&gt;, which takes the name of the original method and the name of the feature and does this mapping for us.&lt;br /&gt;
&lt;br /&gt;
Therefore, the two &lt;span style="font-family: courier new; font-weight: bold;"&gt;alias_method&lt;/span&gt; calls above can be replaced with the following:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;alias_method_chain :render, :feature&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
You, the fine engineer, will define a method &lt;span style="font-family: courier new; font-weight: bold;"&gt;render_with_feature&lt;/span&gt; and the &lt;span style="font-family: courier new; font-weight: bold;"&gt;render&lt;/span&gt; symbol will point to it.  And, after the &lt;span style="font-family: courier new; font-weight: bold;"&gt;alias_method_chain&lt;/span&gt; call, you will have a new &lt;span style="font-family: courier new; font-weight: bold;"&gt;render_without_feature&lt;/span&gt; method created for you.&lt;br /&gt;
&lt;br /&gt;
I find all of this rather elegant and hope this has been helpful&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-1103789426766848179?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/ZJZNYyhZwg0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/ZJZNYyhZwg0/rails-aliasmethodchain-explained-with.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/__7xcUyenJzo/S_VWJNBEoTI/AAAAAAAAACA/ylZ8ezzcDgc/s72-c/alias_method_img_1.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2010/05/rails-aliasmethodchain-explained-with.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-1224027542918086064</guid><pubDate>Sun, 17 Jan 2010 18:36:00 +0000</pubDate><atom:updated>2010-01-17T16:34:38.234-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><title>Spike: Analyzing Rails Development Logs</title><description>As venerable as '&lt;span style="font-family: courier new;"&gt;tail -f log/development.log'&lt;/span&gt; is to a Rails developer (and as undeniably useful as well), I've been using another tool that has been tremendously helpful in weeding through all the noise.  &lt;a href="http://lucidmac.com/products/spike"&gt;Spike&lt;/a&gt;, written by Matt Mower with help from the Rails community, parses your development log and presents, in two windows, summary information and a detailed view.&lt;br /&gt;&lt;br /&gt;Spike lets me see the flow of the application by filtering out records that aren't pertinent to what I'm looking for.  For example, the 5 second refresh event coming in from EVERY browser -- ZAP and they're gone!  I can filter by request, IP, session ID and so on.  The detail viewer shows me all the parameters, the renders and all the activity in the log that is part of the request.&lt;br /&gt;&lt;br /&gt;This has been a very helpful tool; my thanks to Matt and everyone who worked on Spike!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-1224027542918086064?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/9cdvLcXZuLE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/9cdvLcXZuLE/spike-analyzing-rails-development-logs.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>1</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2010/01/spike-analyzing-rails-development-logs.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-6328178135676416750</guid><pubDate>Sat, 16 Jan 2010 22:53:00 +0000</pubDate><atom:updated>2010-01-16T17:57:22.884-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">code</category><category domain="http://www.blogger.com/atom/ns#">advice</category><title>Lesson that I keep learning</title><description>While writing specs I keep learning this lesson over and over.  After calling methods on your data model and saving it to the database, call the &lt;span style="font-family: courier new;"&gt;reload&lt;/span&gt; method to refresh your model.  Otherwise, subsequent operations will be performed on stale data.&lt;br /&gt;&lt;br /&gt;Do this in your engines and other business logic components that change &amp;amp; persist data.  When calling myObject.do_something, which changes and saves internal state &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; you need to continue using myObject in the rest of your method, first call myObject.reload.&lt;br /&gt;&lt;br /&gt;There.  I've gotten it off my chest and I feel better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-6328178135676416750?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/_7hSBl3uqtc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/_7hSBl3uqtc/lesson-that-i-keep-learning.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2010/01/lesson-that-i-keep-learning.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-4703881094541378481</guid><pubDate>Sat, 16 Jan 2010 02:09:00 +0000</pubDate><atom:updated>2010-01-15T21:24:28.600-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">rspec</category><category domain="http://www.blogger.com/atom/ns#">development</category><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>VICTORY: FactoryGirl and Database Rollbacks that Failed</title><description>Draw near my children and listen to a terrible tale of trial, tribulation, twisting torment, teething, temper-tantrums, truculence, and truancy.  Except the teething part.  And there may have been truffles.&lt;br /&gt;&lt;br /&gt;Seriously, I was ready to walk away from FactoryGirl.  Perhaps you have heard of FactoryGirl, yes?  Perhaps you have encountered records left in the database after the test completes.  Perhaps you Google for all sorts of phrases like "FactoryGirl records left database" or "FactoryGirl rollback".  Perhaps you scoured Google groups, the rdocs and all of that stuff.  Yah, me too.&lt;br /&gt;&lt;br /&gt;Yes, "use_transactional_fixtures" was true and "use_instantiated_fixtures" was false.  I searched the entire code base.  So did you.&lt;br /&gt;&lt;br /&gt;But, I'm using rspec, so there is no test_helper.  Spec_helper has slightly different syntax from test_helper, so "self.use_transactional_fixtures" won't work.  You're using FactoryGirl, so you don't have any fixtures.  I deleted mine; get that cruft out of the way.  Heck, I deleted my entire &lt;span style="font-style: italic;"&gt;test&lt;/span&gt; directory!&lt;br /&gt;&lt;br /&gt;But I finally got it.  And it seems so easy now.  Like childs play, just like in &lt;a href="http://en.wikipedia.org/wiki/Spock%27s_Brain"&gt;Spock's Brain&lt;/a&gt;, when McCoy had to re-attach Spock's brain.  And, hopefully this will help you too.&lt;br /&gt;&lt;br /&gt;Make sure you have a &lt;span style="font-weight: bold;"&gt;fixtures&lt;/span&gt; directory. Mine is in RAILS_ROOT/spec, so I added the following line to my spec_helper.rb:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  config.fixture_path = RAILS_ROOT + '/spec/fixtures/'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then I told Spec::Runner that I had fixtures, &lt;span style="font-style: italic;"&gt;even though the directory is empty!&lt;/span&gt;  There is a fixture entry for every table that was not getting reset.  For example, the users table was not getting reset, so I set:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; config.global_fixtures = :users&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And, when I needed the players table cleared, I added the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; config.global_fixtures = :users, :players&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's it!  All better.  Rspec now clears up those tables just as purty as you please and the tests are passing -- big bars o' green!  Yippee!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-4703881094541378481?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/gLEXVQleb2w" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/gLEXVQleb2w/victory-factorygirl-and-database.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2010/01/victory-factorygirl-and-database.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-6537913407639310656</guid><pubDate>Tue, 12 Jan 2010 02:06:00 +0000</pubDate><atom:updated>2010-01-11T21:20:10.883-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>Good Ruby on Rails Tools</title><description>I'm looking at the following tools to add to my Ruby on Rails tool chain:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Continuous Integration&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;RunCodeRun at &lt;a href="http://runcoderun.com/"&gt;runcoderun.com&lt;/a&gt;&lt;br /&gt;CruiseControl by &lt;a href="http://cruisecontrolrb.thoughtworks.com/"&gt;Thoughtworks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Scalability&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm excited by the products talked about at the NewRelic &lt;a href="http://railslab.newrelic.com/2009/10/23/episode-19-on-the-edge-part-1"&gt;s&lt;/a&gt;&lt;a href="http://railslab.newrelic.com/2009/10/23/episode-19-on-the-edge-part-1"&gt;calability blog&lt;/a&gt;. I saw the first episode and am very psyched about &lt;a href="http://github.com/flyerhzm/bullet"&gt;bullet&lt;/a&gt; by Richard Huang.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Metrics &amp;amp; Monitoring&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Can't wait to try out &lt;a href="http://getcaliper.com/"&gt;Caliper&lt;/a&gt; for Ruby metrics and &lt;a href="http://newrelic.com"&gt;NewRelic&lt;/a&gt; for monitoring&lt;br /&gt;&lt;br /&gt;I'm using SVN on a few projects, but I have been in the promised land and can't wait to get back to git, so let's add &lt;a href="http://github.com/plans"&gt;GitHub&lt;/a&gt; to the list.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-6537913407639310656?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/ae7OukN9-7A" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/ae7OukN9-7A/good-ruby-on-rails-tools.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2010/01/good-ruby-on-rails-tools.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-1971528228117965844</guid><pubDate>Fri, 13 Nov 2009 23:44:00 +0000</pubDate><atom:updated>2009-11-13T18:58:14.739-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">aasm</category><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">solution</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>Event callbacks in AASM</title><description>Having written about AASM in the past, first on &lt;a href="http://degenportnoy.blogspot.com/2009/10/chaining-state-transitions-with-acts-as.html"&gt;Chaining state transitions with Acts As State Machine (aasm)&lt;/a&gt;, and then again in &lt;a href="http://degenportnoy.blogspot.com/2009/10/conditional-state-transitions-with-aasm.html"&gt;Conditional state transitions with AASM&lt;/a&gt;, I thought I had AASM down rather pat.&lt;br /&gt;&lt;br /&gt;However, when I tried adding a callback to the aasm_event, I ran into trouble.  Quite simply, the callback never worked.  Here's the first code:&lt;br /&gt;&lt;script src="http://pastie.org/698107.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Notice that the callback registration is in the aasm_event code block.  It seemed reasonable that this would be part of the transition.  When I determined that this was not working, I had a colleague review the code and we ended up both scratching our heads.&lt;br /&gt;&lt;br /&gt;So, I cracked open the library and poked around.  I saw the successful aasm_state call displaying the callback registration in the options portion of the method, but the options of the aasm_event were blank.  Hmm!&lt;br /&gt;&lt;br /&gt;Here are the method definitions for your edification:&lt;br /&gt;&lt;b&gt;aasm_state&lt;/b&gt;(name, options={})                                    &lt;br /&gt;&lt;b&gt;aasm_event&lt;/b&gt;(name, options = {}, &amp;amp;block)                                    &lt;br /&gt;&lt;br /&gt;Well, it was pretty clear how to fix the problem; move the callback registration after the name argument and before the block.  Here's the corrected code:&lt;br /&gt;&lt;script src="http://pastie.org/698120.js"&gt;&lt;/script&gt;&lt;br /&gt;That's it!  Have fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-1971528228117965844?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/RG65-gnkD3Y" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/RG65-gnkD3Y/event-callbacks-in-aasm.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>2</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/11/event-callbacks-in-aasm.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-2487467734833104511</guid><pubDate>Fri, 30 Oct 2009 10:36:00 +0000</pubDate><atom:updated>2009-10-30T06:43:06.995-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">opinion</category><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">software</category><title>Fast Online Documentation - GotAPI.com</title><description>When I'm coding and have an API question, I have one and only one demand from my documentation source -- speed.  I want to be able to quickly find the information I seek.  "Now.  I want it now."&lt;br /&gt;&lt;br /&gt;I use PDF versions of my favorite books and the generated Ruby 2.3.4 API documentation locally, which is all good, but I found something that may be even better.  &lt;a href="http://www.gotapi.com/rubyrails"&gt;GotAPI&lt;/a&gt; has a clean interface, is wicked fast and utterly intuitive.  It even holds your recent searches.&lt;br /&gt;&lt;br /&gt;In addition to lightning fast Ruby and Ruby on Rails look ups, it has tabs for HTML, Javascript DOM and CSS; all the things I need during RoR development!&lt;br /&gt;&lt;br /&gt;I've added it to my browser bar so I can get to it quickly and it's rapidly becoming my reference tool of choice.  Highly recommended.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-2487467734833104511?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/OnTuakEVwoI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/OnTuakEVwoI/fast-online-documentation.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/10/fast-online-documentation.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-5969541243246656165</guid><pubDate>Sat, 10 Oct 2009 12:30:00 +0000</pubDate><atom:updated>2011-12-09T07:35:27.688-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">aasm</category><category domain="http://www.blogger.com/atom/ns#">development</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>Conditional state transitions with AASM</title><description>Also part of the same state machine I wrote about in "&lt;a href="http://degenportnoy.blogspot.com/2009/10/chaining-state-transitions-with-acts-as.html"&gt;Chaining state transitions with Acts As State Machine (aasm)&lt;/a&gt;" required two different types of behavior for a state transition.&lt;br /&gt;
&lt;br /&gt;
The task reviewer state was optional and would be triggered only if selected.  I represented that state as a "use_reviewer" boolean column in the object.  If &lt;span style="font-family: courier new;"&gt;use_reviewer == true&lt;/span&gt;, then the object transitions from task_created to "to_reviewer", otherwise it needed to transition to "to_writer"&lt;br /&gt;
&lt;br /&gt;
The solution to this is rather straight forward.  Use the :guard option in the aasm_event definition.&lt;br /&gt;
&lt;br /&gt;
Here's the code:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  aasm_event :created do&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;    transitions :to =&amp;gt; :to_reviewer, :from =&amp;gt; [:task_created], :guard =&amp;gt; Proc.new {|p| p.use_reviewer == true }&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;    transitions :to =&amp;gt; :to_writer, :from =&amp;gt; [:task_created]&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  end&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The event causes the  object to transition to the "to_reviewer" state if the objects "use_reviewer" is true, otherwise it transitions to "to_writer".  Here's the code evidence from script/console:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a = Assignment.new&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; (Assignment object)&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.use_reviewer = true&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; true&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.save&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; true&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.created!&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; true&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.aasm_current_state&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; :to_reviewer&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now we start over:&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a = Assignment.new&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt;(Assignment object)&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.save&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; true&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.created!&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; true&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&amp;gt;&amp;gt; a.aasm_current_state&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;=&amp;gt; :to_writer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-5969541243246656165?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/IPx2L69eGJo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/IPx2L69eGJo/conditional-state-transitions-with-aasm.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/10/conditional-state-transitions-with-aasm.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-693909077422107728</guid><pubDate>Sat, 10 Oct 2009 11:14:00 +0000</pubDate><atom:updated>2011-12-09T07:36:36.787-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">aasm</category><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">code</category><category domain="http://www.blogger.com/atom/ns#">advice</category><title>Chaining state transitions with Acts As State Machine (aasm)</title><description>Have you ever had state transition requirements that required automatic chaining of transition changes?  I've got a system that transitions to a "to_reviewer" state after it has been created.&lt;br /&gt;
&lt;br /&gt;
In the "to_reviewer" state, a group of reviewers are presented the assignment and they may accept the assignment, or a project manager may assign the assignment to a reviewer: in either case, as soon as there is a reviewer assigned, the assignment transitions to the "reviewer" state.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://1.bp.blogspot.com/__7xcUyenJzo/StBvybLVGoI/AAAAAAAAAAw/gTw-e0Y87FY/s1600-h/Cascading+State+Change.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5390931666041903746" src="http://1.bp.blogspot.com/__7xcUyenJzo/StBvybLVGoI/AAAAAAAAAAw/gTw-e0Y87FY/s320/Cascading+State+Change.png" style="cursor: pointer; display: block; height: 300px; margin: 0px auto 10px; text-align: center; width: 300px;" /&gt;&lt;/a&gt;However, if the system already has a reviewer assigned at the "created" event, then it should cascade the state transition change and go directly to "reviewer" without staying in "to_reviewer"&lt;br /&gt;
&lt;br /&gt;
Having selected the &lt;a href="http://github.com/rubyist/aasm"&gt;Rubyist AASM&lt;/a&gt; gem to implement my state machine in this Ruby on Rails project, I expected that I would be able to use the :after options of the aasm_state statement.  I got that idea from the README.rdoc for version 2.1.1, which lists "event:after" in the callback chain.&lt;br /&gt;
&lt;br /&gt;
However, the :after callback is called on an event (aasm_event) and I can't find documentation on how to hook into that callback.  Digging into the the code, I found the following syntax works correctly in my Assignment object (derived from ActiveRecord).  The solution is to use the :after_event option in the aasm_state definition statement.&lt;br /&gt;
&lt;br /&gt;
This first part defines the states:&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  aasm_initial_state :task_created&lt;br /&gt;aasm_state :task_created&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  aasm_state :to_reviewer, :after_enter =&amp;gt; :check_reviewer&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  aasm_state :reviewer&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This next part defines the events:&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  aasm_event :created do&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;     transitions :to =&amp;gt; :to_reviewer, :from =&amp;gt; [:task_created]&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;  end&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  &lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  aasm_event :task_review do&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;     transitions :to =&amp;gt; :reviewer, :from =&amp;gt; [:to_reviewer]&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  end&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This last part is the definition of the :after_enter method:&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;  def check_task_reviewer&lt;br /&gt; task_review unless reviewer_id.blank?&lt;br /&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now, when the object is created, the aasm_current_state is "task_created".  If the object receives the "created" event, it transitions to the "to_reviewer" state.  However, after the object enters the "to_reviewer" state, the "check_task_reviewer" method advances the state again if a reviewer as been assigned (indicated by the presence of the reviewer_id).&lt;br /&gt;
&lt;br /&gt;
Checking the code in the console, we get:&lt;br /&gt;
&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&amp;gt;&amp;gt; a = Assignment.new&lt;br /&gt;=&amp;gt; (Assignment object information)&lt;br /&gt;&amp;gt;&amp;gt; a.reviewer_id = 5&lt;br /&gt;=&amp;gt; 5&lt;br /&gt;&amp;gt;&amp;gt; a.save&lt;br /&gt;=&amp;gt; true&lt;br /&gt;&amp;gt;&amp;gt; a.created!&lt;br /&gt;=&amp;gt; true&lt;br /&gt;&amp;gt;&amp;gt; a.aasm_current_state&lt;br /&gt;=&amp;gt; :reviewer&lt;/span&gt;&lt;br /&gt;
And we can see that the object transitioned through the "to_reviewer" state an on into the "reviewer"state.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-693909077422107728?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/_LhgYF2mobw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/_LhgYF2mobw/chaining-state-transitions-with-acts-as.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/__7xcUyenJzo/StBvybLVGoI/AAAAAAAAAAw/gTw-e0Y87FY/s72-c/Cascading+State+Change.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/10/chaining-state-transitions-with-acts-as.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-7981989013430532796</guid><pubDate>Thu, 08 Oct 2009 19:03:00 +0000</pubDate><atom:updated>2009-10-08T15:09:29.452-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ruby on rails</category><title>The Ruby Toolbox</title><description>I've had the good fortune to stumble across &lt;a href="http://ruby-toolbox.com"&gt;The Ruby Toolbox&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This delightful site is filled with collections of helpful, nifty plugins and gems that help make the life of any Ruby and/or Rails developer much more pleasant.  There are some 75+ different categories that deal with ActiveRecord, Backups, Code Metrics, CSS Frameworks, E-Commerce, Game Libraries, Gem Creation, and on, and on.&lt;br /&gt;&lt;br /&gt;Not only are projects, gems &amp; plugins listed, but they are rated in terms of how much attention the project is receiving.  The most popular projects are listed at the top with an attractive scale along side to the right to help you compare the popularity of different options.&lt;br /&gt;&lt;br /&gt;If you're doing Ruby and/or Rails development and haven't visited this site, then you really deserve to do yourself a favor.  I'm headed there now!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-7981989013430532796?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/Z-unLwt7r-M" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/Z-unLwt7r-M/ruby-toolbox.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/10/ruby-toolbox.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-4023375502391313226</guid><pubDate>Thu, 01 Oct 2009 20:47:00 +0000</pubDate><atom:updated>2011-12-09T07:37:09.785-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">development</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">code</category><title>Rails Trick: Access an ActiveRecord field in a loop in a view</title><description>I came up with a little trick that I want to share, even though I'm sure there are better ways of doing this (perhaps someone will suggest them!)&lt;br /&gt;
&lt;br /&gt;
OK, picture this:  We have over half a dozen different types of workers -- Writers, Sr. Editors, Editors, etc. -- and we're going to pay them.  So, in the database we have things like &lt;span style="font-family: courier new; font-size: 85%;"&gt;writer_payment, sr_editor_payment and editor_payment&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
In the edit view, we have something like this (actually, there are many more cells, but I've omitted them for clarity):&lt;br /&gt;
&lt;br /&gt;
&lt;script src="http://pastie.org/638674.js"&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
And, I fully expect that we will be adding many more workers, so we can look forward to much cutting and pasting.&lt;br /&gt;
&lt;br /&gt;
Well, I wanted to come up with a way of declaring an array, iterating through it and creating each row automagically.&lt;br /&gt;
&lt;br /&gt;
My first thought was this:&lt;br /&gt;
&lt;br /&gt;
&lt;script src="http://pastie.org/638676.js"&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
But this doesn't work at all.  The ActiveRecord attribute can't be built dynamically with string interpolation in the view.  Similar efforts failed miserably.&lt;br /&gt;
&lt;br /&gt;
But then I took at look at the &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002348"&gt;ActiveRecord::Base&lt;/a&gt; class and noticed the attributes method.  This got me a-thinkin' and here's what I came up with.  Get the attributes from the ActiveRecord.  Build a string with the array value and the "_payment", use straight array access to get the payment value&lt;br /&gt;
&lt;br /&gt;
&lt;script src="http://pastie.org/638696.js"&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
And, Holy Smakeral -- it works!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-4023375502391313226?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/hXby8vfjQyk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/hXby8vfjQyk/rails-trick-access-activerecord-field.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/10/rails-trick-access-activerecord-field.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-5676269293549418404</guid><pubDate>Sun, 27 Sep 2009 22:20:00 +0000</pubDate><atom:updated>2009-09-27T18:28:56.195-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DIY</category><category domain="http://www.blogger.com/atom/ns#">advice</category><title>Great Website for Printing Patents</title><description>It's been a busy day and I'm finishing it with some patent work.  I wanted to share a really great discovery.  &lt;a href="http://www.pat2pdf.org"&gt;PAT2PDF&lt;/a&gt; is a free site that seems to be somewhat supported by donations (I made one!).  The site accepts a search phrase for the following types of items:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;US Utility Patent&lt;/li&gt;&lt;li&gt;US Pre-Grant Publication&lt;/li&gt;&lt;li&gt;US Design Patent&lt;/li&gt;&lt;li&gt;US Plant Patent&lt;/li&gt;&lt;li&gt;US Reissue&lt;/li&gt;&lt;li&gt;US Statutory Invention Reg.&lt;/li&gt;&lt;/ul&gt;You can even issue multiple requests by separating terms with semicolons.&lt;br /&gt;&lt;br /&gt;The site looks up your item, pulls it from the US Patent Office's website and assembles it into a single PDF for download.  Sweet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-5676269293549418404?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/oTk0t_mvdsU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/oTk0t_mvdsU/great-website-for-printing-patents.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/09/great-website-for-printing-patents.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-1133119317222001209</guid><pubDate>Sun, 27 Sep 2009 21:00:00 +0000</pubDate><atom:updated>2009-09-27T18:34:33.574-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">repair</category><category domain="http://www.blogger.com/atom/ns#">DIY</category><title>What I Learned About Garage Door Openers</title><description>A friend's garage door opener wasn't opening the door although the motor was running.  I offered to try and repair it.  After all, it already wasn't working; what was the harm?&lt;br /&gt;&lt;br /&gt;After opening the cover the problem was obvious.  The nylon gear which drove the shaft that drove the sprocket (which is a gear that is driven by or drives a chain), was split in half.  I looked up the manufacturer on the 'Net, then the model number and ordered a replacement kit.  I was &lt;span style="font-weight: bold;"&gt;so&lt;/span&gt; relieved that it came with a detailed instruction book!&lt;br /&gt;&lt;br /&gt;Here's what I learned about this garage door opener:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Limit Switches&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The limit switches are very simple.  As the drive shaft turns, it drives a screw upon which is mounted a moving contact.  As the screw turns, it moves the contact to one end or the other. One screw on each side of the moving contact has the other end of the contact.  As soon as the moving contact meets the end contacts -- the door stops.  Simple!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rate Sensor&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;There is a rate sensor that measures the rate at which the motor is spinning.  This was also simple.  A cap on the motor shaft had a series of four slots and openings, which passed through a sensor with a tiny emitter and sensor.  If the door gets blocked, the motor can't turn.  If the motor can't turn and the unit has not hit one of the limit switches, and the door is moving down, the controller reverses direction.   If the door is moving up, it stops.  Simple!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Retaining Pins&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;There isn't any other way to get a retaining pin out other than with a hammer.  The sprocket drive shaft holds the drive gear in place with two retaining pins.  These fit tightly into place.  I had to drive the lower pin out in order to slide the new drive gear into place and the only way to do that was with a hammer.  As soon as the pin was flush with the shaft, I used a punch to continue driving the pin through the shaft.  After the new drive gear was in place, it was hammering once again to get the pin back into position.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Disassembly &amp;amp; Reassembly&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Check the orientation of things as you disassemble them.  I made two good choice and missed on opportunity.  Before unplugging drive motor power connectors, I confirmed that the diagram in the instruction booklet was accurate and took a picture of the setup with my phone.  When re-assembling the unit, I had all the documentation that I needed.  However, I didn't notice  the tabs in the top plate that holds the drive shaft in position and ended up re-installing that plate rotated 1/3 around.  I didn't notice the mistake until nearly the very last step of re-installing the protective plastic cap over the sprocket and drive chain.  It didn't make sense to disassemble the entire unit at that point, so we're living with my error.  Had I taken a picture of that unit before disassembling it, I would have had the necessary reference.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Clean Grease&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Clean grease isn't so bad.  Dirty grease is wicked icky, but the new clean grease was easy to put on and I didn't mind cleaning up afterwards.&lt;br /&gt;&lt;br /&gt;End of the story: the garage door works perfectly now.  And I had a lot of fun taking the durn thing apart and putting it together!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-1133119317222001209?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/rPUz7WzTq6c" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/rPUz7WzTq6c/what-i-learned-about-garage-door.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/09/what-i-learned-about-garage-door.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-19901248.post-788536106162319135</guid><pubDate>Sun, 27 Sep 2009 12:47:00 +0000</pubDate><atom:updated>2009-09-27T18:17:20.267-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">DIY</category><category domain="http://www.blogger.com/atom/ns#">technology</category><category domain="http://www.blogger.com/atom/ns#">software</category><category domain="http://www.blogger.com/atom/ns#">computer</category><title>Configuring Drupal for McNiff Plumbing &amp; Heating</title><description>As mentioned in my last post on &lt;a href="http://degenportnoy.blogspot.com/2009/09/selecting-drupal-for-mcniff-plumbing.html"&gt;Selecting Drupal for McNiff Plumbing &amp;amp; Heating&lt;/a&gt;, I wanted to talk about configuring Drupal for a mostly static site.&lt;br /&gt;&lt;br /&gt;The requirements are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Anonymous Users can view all content&lt;/li&gt;&lt;li&gt;The site is Page oriented; Home, Services, Comments, Contact Us&lt;/li&gt;&lt;li&gt;No navigation menu&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No login options visible to anonymous users&lt;/li&gt;&lt;li&gt;No content titles, author information or posting dates on pages&lt;/li&gt;&lt;li&gt;No user comment links&lt;/li&gt;&lt;/ul&gt;To start with, I went to Administer &gt;&gt; Site Building &gt;&gt; Blocks and disabled nearly all the blocks.  I changed the Navigation block to be visible only to Authenticated Users.&lt;br /&gt;&lt;br /&gt;I then created the following pages: Home, Services &amp;amp; Comments and copied some of the content from the current site as a place holder.  I also set the Menu Title Links in each of these pages to their base name, so that it could be referenced from a menu.&lt;br /&gt;&lt;br /&gt;I used Administer &gt;&gt; Site Building &gt;&gt; Menus &gt;&gt; Primary Links to add a menu item for each page.&lt;br /&gt;&lt;br /&gt;Next up was creating the Contact Us form.  I enabled the Contact module in the Core - optional section, wen to "Administer By Module" and configured the permissions for the Contact Form and enabled "access site-wide contact form" for all users.&lt;br /&gt;&lt;br /&gt;Back to the Menus to add a new Primary Link menu option for Contact by specifying the "contact" page as the target.  After saving this new menu item, it was showing up as a new tab with the other menu pages.  Great!&lt;br /&gt;&lt;br /&gt;Let's check for an anonymous users.  I opened up a different browser (I just hate logging out and in and out and in) and checked the development site.  No joy in Mudville -- and no tab either.&lt;br /&gt;&lt;br /&gt;Somewhere along the line, I was missing permissions.  I checked and double checked that the menu was enabled and that anonymous users could access the contact form.  I even typed the path into the other browser and the form displayed.  Hmmm; not a permission problem because the anonymous user &lt;span style="font-weight: bold;"&gt;could&lt;/span&gt; see the form.  The navigation link was simply not being displayed.&lt;br /&gt;&lt;br /&gt;Back to Administer &gt;&gt; Site Building &gt;&gt; Contact Form &gt;&gt; Edit.  There is a "Selected" option, which was set to "No".  Changing that to "Yes" turned on the tab in the Anonymous User's view.&lt;br /&gt;&lt;br /&gt;Yea!&lt;br /&gt;&lt;br /&gt;Next up; clean up the pages to show only the pieces of information we want.  This might require a custom View.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19901248-788536106162319135?l=degenportnoy.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MondayByDegenPortnoy/~4/hDC8XMIf9c4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/MondayByDegenPortnoy/~3/hDC8XMIf9c4/configuring-drupal-for-mcniff-plumbing.html</link><author>noreply@blogger.com (Peter Degen-Portnoy)</author><thr:total>0</thr:total><feedburner:origLink>http://degenportnoy.blogspot.com/2009/09/configuring-drupal-for-mcniff-plumbing.html</feedburner:origLink></item></channel></rss>

