<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Heedspin</title>
    <link href="http://www.heedsipn.com/atom.xml" rel="self"/>
    <link href="http://www.heedspin.com/"/>
    <updated>2017-08-23T17:46:25+00:00</updated>
    <id>http://www.heedspin.com/</id>    
    
		
    <entry>
        <title>Unconvincing Opinions</title>
        
        <link href="http://www.heedspin.com/2012/12/24/unconvincing-opinions.html"/>
        <updated>2012-12-24T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2012/12/24/unconvincing-opinions</id>
        <content type="html">&lt;p&gt;The Sandy Hook Massacre has inspired an abundance of opinion pieces on gun control. A majority of these publications are what I’ll call “unconvincing opinions:” articles on controversial subjects that make no attempt to engage the opposition. While readers who already agree may feel justification, those with opposing views will likely just become angry. I don’t see the purpose of writing an unconvincing opinion, unless the goal is to stir opposition.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;http://www.northjersey.com/news/opinions/184586301_The_Record__Gun_sense.html&quot;&gt;unconvincing post on NorthJersey.com&lt;/a&gt; is what inspired the present post. At one point the author wished “the NRA would present sober and thoughtful solutions.” But in the same post he calls for the reinstatement of every past gun control law as well as revising the second amendment of the U.S. Constitution. Gun control proponents may love this type of talk, but those against will likely be moved to fight. I hope the author reads the post comments and recognizes the irony.&lt;/p&gt;

&lt;h2 id=&quot;responsibility-to-persuade&quot;&gt;Responsibility To Persuade&lt;/h2&gt;

&lt;p&gt;I can see why unconvincing opinion pieces exists. Articles like the NorthJersey post appear to be emotionally inspired. This is as it should be, since &lt;a href=&quot;http://www.psychologytoday.com/blog/intense-emotions-and-strong-feelings/201012/it-or-not-emotions-will-drive-the-decisions-you-mak&quot;&gt;purpose of emotions is to move us to action&lt;/a&gt;. Furthermore, &lt;a href=&quot;http://scottwb.com/blog/2012/02/09/inspiration-is-perishable/&quot;&gt;inspiration is perishable&lt;/a&gt;, so wise writers act while the blood is still boiling.&lt;/p&gt;

&lt;p&gt;But I’d like to suggest that, in addition to the other great responsibilities inherent to journalism, writers have a responsibility to persuade. On topics of controversy, opinion authors have a responsibility to pursue peace. Even if an author’s opinion is 100% correct, what good is it when presented such that the opposition can’t hear? Indeed if you hold the truth, you have a responsibility to share it, and to do so effectively!&lt;/p&gt;

&lt;p&gt;Though I never saw the 2006 movie &lt;em&gt;The Last King of Scotland&lt;/em&gt;, I never forgot this scene from one of the previews. Just knowing the truth is worthless! It’s your job to be persuasive!&lt;/p&gt;

&lt;div class=&quot;breakout mod&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/5VMX6zCXHWA&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id=&quot;how-to-persuade&quot;&gt;How To Persuade&lt;/h2&gt;

&lt;p&gt;To persuade adversaries, a good first step should be to understand their premise. &lt;a href=&quot;http://econlog.econlib.org/archives/2011/06/the_ideological.html&quot;&gt;Bryan Caplan says&lt;/a&gt;: “If someone can correctly explain a position but continue to disagree with it, that position is less likely to be correct.”  He also quotes &lt;a href=&quot;http://www.goodreads.com/quotes/66643-he-who-knows-only-his-own-side-of-the-case&quot;&gt;John Stuart Mill&lt;/a&gt; who says: “he must know [the opinions of adversaries] in their most plausible and persuasive form.”&lt;/p&gt;

&lt;p&gt;In this &lt;a href=&quot;http://douthat.blogs.nytimes.com/2012/07/26/on-gun-control-and-prohibition/&quot;&gt;excellent post on gun control by Ross Douthat&lt;/a&gt; (pre Sandy Hook), he starts out by recognizing the validity of an argument for gun control. Then he finishes with an argument against gun control written almost as a suggestion for consideration. Though the article has a pro-gun conclusion, it’s accessible from both sides of the controversy. In facilitating mutual understanding, this is a model example of steady persuasion on a subject that typically only stirs tempers.&lt;/p&gt;

&lt;h2 id=&quot;demand-to-be-persuaded&quot;&gt;Demand To Be Persuaded&lt;/h2&gt;

&lt;p&gt;My hope is that more writers would engage in persuasive discourse. Perhaps they exist, but are not promoted to the top of the news sources I frequent. If news sites prioritize opinion posts based on popularity, does the blame return to us readers? Convincing and persuasive writings are not promoted because we do not demand them (and do not share them on Facebook and Twitter)?&lt;/p&gt;

&lt;p&gt;Let’s be like Forest Whitaker in &lt;em&gt;The Last King of Scotland&lt;/em&gt; and shock our writers with their responsibility to persuade. In fact, I think I’ll use this response next time someone offends me with an unconvincing opinion: “You may be right, but you have failed to persuade me.”&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>What I learned from Paul Ryan</title>
        
        <link href="http://www.heedspin.com/2012/08/24/what-i-learned-from-paul-ryan.html"/>
        <updated>2012-08-24T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2012/08/24/what-i-learned-from-paul-ryan</id>
        <content type="html">&lt;p&gt;
	&lt;img src=&quot;/images/pdr/paul_with_crowd.png&quot; width=&quot;500&quot; /&gt;
	&lt;span class=&quot;caption&quot;&gt;Look at all those people!&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;I recently had the privilege of helping host Vice Presidential Candidate, Rep. Paul Ryan for a rally at &lt;a href=&quot;http://www.smtcoinc.com&quot;&gt;SMT Inc.&lt;/a&gt; in Raleigh, North Carolina. Politics aside, anyone witnessing such an event would be impressed. Here are some things I learned from Paul Ryan’s visit:&lt;/p&gt;

&lt;h2 id=&quot;you-can-do-a-lot-in-2-days&quot;&gt;You Can Do A Lot in 2 Days&lt;/h2&gt;

&lt;p&gt;I’m not sure how long the Republican party was considering SMT as venue, but we got official word on Sunday night for a Wednesday event. SMT and &lt;a href=&quot;http://www.creativevisions.com/&quot;&gt;Creative Visions&lt;/a&gt; turned a regular factory floor into a political rally venue in two days. Stages, bleachers, rafter lights, a full sound system, and everything. The whole event went perfectly. I didn’t see a single hiccup.&lt;/p&gt;

&lt;div class=&quot;breakout mod&quot;&gt;
	&lt;p&gt;
		&lt;img src=&quot;/images/pdr/shopfloor_before.png&quot; width=&quot;500&quot; /&gt;
		&lt;span class=&quot;caption&quot;&gt;Cleaned and ready&lt;/span&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;img src=&quot;/images/pdr/shopfloor_before2.png&quot; width=&quot;500&quot; /&gt;
		&lt;span class=&quot;caption&quot;&gt;Setting up&lt;/span&gt;
	&lt;/p&gt;
	&lt;p&gt;
		&lt;img src=&quot;/images/pdr/shopfloor_before3.png&quot; width=&quot;500&quot; /&gt;
		&lt;span class=&quot;caption&quot;&gt;Just add people!&lt;/span&gt;
	&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;By the way, while these guys were creating a venue from scratch, all of the Republican staffers were working past midnight planning every detail of Paul Ryan’s visit: Which hallway does he walk down, who does he talk to, for how long, and on and on. One of the staff put it to me this way: “We’re the frantic duck feet underwater; the event is the calm duck”.  So… that would make me the slimy pond water?  I like it!&lt;/p&gt;

&lt;h2 id=&quot;political-candidates-work-hard&quot;&gt;Political Candidates Work Hard&lt;/h2&gt;

&lt;p&gt;I understand not everyone will agree with Rep. Paul Ryan’s politics. But I’m here to tell you: the man works hard. The Secret Service cleared me for access into the same areas as Congressman Ryan, so I witnessed his life for about 5 hours.&lt;/p&gt;

&lt;p&gt;Paul Ryan started the day in Virginia. He arrived at SMT in Raleigh, NC and immediately did some photos with VIPs and a couple on-camera press interviews. Then he gave the big 30-minute speech to thousands of supporters. Immediately following the rally, he spent about 2 hours meeting with several teams. At one point he emerged from a room and joked that they had successfully stuffed more information into his head. I spoke with one of his briefing staff and learned that congressman’s head had just been filled with the inner workings of the United Nations. Enthralling, I’m sure.&lt;/p&gt;

&lt;p&gt;After all the meetings, he took a few more VIP photos while the entourage began moving towards the exit. Almost out the door, he stopped and asked an aid who he could thank before leaving. Only a coworker and I were around, so he came over and thanked us. I said “you’re welcome” and then peed my pants.&lt;/p&gt;

&lt;p&gt;And in a flash he was gone. And all the Secret Service and police disappeared with him. Two hours later the stage was gone too, and I think I saw a tumbleweed blow across the factory floor. I was in bed and asleep an hour after that.&lt;/p&gt;

&lt;p&gt;But Rep. Paul Ryan wasn’t done. They &lt;a href=&quot;http://www2.nbc17.com/news/2012/aug/22/vice-presidential-candidate-paul-ryan-st-36845-vi-50646/&quot;&gt;stopped at a lemonade stand&lt;/a&gt; on the way to his &lt;a href=&quot;http://abcnews.go.com/blogs/politics/2012/08/paul-ryans-hosts-at-north-carolina-fundraiser/&quot;&gt;big fund raiser&lt;/a&gt; that evening.  One of his aids told me he had a 2-hour phone call scheduled for the drive after the fund raiser.&lt;/p&gt;

&lt;p&gt;When does he sleep?&lt;/p&gt;

&lt;h2 id=&quot;the-secret-service-is-awesome&quot;&gt;The Secret Service Is Awesome&lt;/h2&gt;

&lt;p&gt;Probably my favorite part of the whole event was hanging out with the Secret Service. These guys are cool. And thorough.&lt;/p&gt;

&lt;p&gt;They have a plan for everything from a power outage to a chemical attack. They bomb-swept this giant building several times. Every nook and cranny was inspected. As they explained to the building manager: “If we find a locked door, we’re breaking it down.” Once all the rooms were swept, if you had to enter a room that would be used by the Representative, you were escorted.&lt;/p&gt;

&lt;div class=&quot;breakout mod&quot;&gt;
	&lt;p&gt;While doing a tour of the building, one of the agents pointed at this sign and laughed at me:&lt;/p&gt;
	&lt;p&gt;
		&lt;img src=&quot;/images/pdr/concealed.png&quot; width=&quot;500&quot; /&gt;
		&lt;span class=&quot;caption&quot;&gt;Unless you&#39;re the SS!&lt;/span&gt;
	&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I also learned that the Secret Service’s &lt;a href=&quot;http://www.secretservice.gov/investigations.shtml&quot;&gt;“primary investigative mission is to safeguard the payment and financial systems of the United States”&lt;/a&gt;. One agent said his office had a record number of fraud arrests this year. I had no idea!&lt;/p&gt;

&lt;p&gt;Maybe it’s a coincidence, but we started having intermittent network issues two days before the event. All the problems stopped after the event and have not recurred. Maybe those dudes have some &lt;a href=&quot;http://www.ncfi.usss.gov/&quot;&gt;serious computer hacking skills&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
	&lt;img src=&quot;/images/pdr/paul_greeting_crowd.png&quot; width=&quot;500&quot; /&gt;
	&lt;span class=&quot;caption&quot;&gt;Men In Black&lt;/span&gt;
&lt;/p&gt;

&lt;h1 id=&quot;bye-see-you-later&quot;&gt;Bye, See You Later…&lt;/h1&gt;

&lt;p&gt;Now maybe I’ll know better next time I see a campaigning politico and think to myself: “I can do that!” I most assuredly can not. Good news: I want not!&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

&lt;p&gt;
	&lt;a href=&quot;http://www.newsobserver.com/2012/08/22/2284931/first-look-paul-ryan-visits-raleigh.html&quot;&gt;
		&lt;img src=&quot;/images/pdr/welcoming_to_smt.png&quot; width=&quot;500&quot; /&gt;
	&lt;/a&gt;
	&lt;span class=&quot;caption&quot;&gt;Susan Rothecker from SMT introducing Paul Ryan&lt;/span&gt;
&lt;/p&gt;

</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Using Any File Format for the Made2Manage CAD Images</title>
        
        <link href="http://www.heedspin.com/2011/11/10/use-any-format-for-made2manage-cad-images.html"/>
        <updated>2011-11-10T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/11/10/use-any-format-for-made2manage-cad-images</id>
        <content type="html">&lt;p&gt;The Made2Manage (M2M) ERP system lets you attach 3 CAD Images to your item master. Like so:&lt;/p&gt;

&lt;p&gt;
	&lt;img src=&quot;/images/m2m-cad-images/cad-images-on-item-master.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;These image locations get copied to jobs in production. Like so:&lt;/p&gt;

&lt;p&gt;
	&lt;a href=&quot;/images/m2m-cad-images/cad-images-in-job.png&quot;&gt;&lt;img src=&quot;/images/m2m-cad-images/cad-images-in-job.png&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The problem is that M2M will try to open these CAD Images using a single application that you configure in your user management. The assumption is that we will only put CAD files there and so we just need to tell M2M where our CAD program is.&lt;/p&gt;

&lt;p&gt;We want to put PDFs and images and CAD files there.  If you’ve read this far, you probably do too.  So here’s what we put in our User Management:&lt;/p&gt;

&lt;p&gt;
	&lt;img src=&quot;/images/m2m-cad-images/user-management.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;We’ve created a little start.bat script that will launch whatever we want.  You ready for the brilliance of start.bat?  Brace yourself.  Seriously…&lt;/p&gt;

&lt;p&gt;
	&lt;img src=&quot;/images/m2m-cad-images/start-bat.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Yup.  It’s that awesome.  The entire file contents are “%1” without the quotes.  I’m no windows expert, but I think it’s the equivalent of just double-clicking the file.  Let windows figure out what app to launch to view your file.&lt;/p&gt;

&lt;p&gt;That’s all.  I hope this helps.&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>M2MHub: Open Source Reports For Made2Manage</title>
        
        <link href="http://www.heedspin.com/2011/09/27/open-source-reports-for-made2manage.html"/>
        <updated>2011-09-27T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/09/27/open-source-reports-for-made2manage</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Impossible_object&quot;&gt;&lt;img src=&quot;/images/m2m.jpg&quot; alt=&quot;Made2Manage Logo&quot; title=&quot;I love that M2M&#39;s logo is an example of an impossible object&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I work with a few companies that use the Made2Manage ERP system. In short, building custom reports in Made2Manage (M2M) is difficult. As a software engineer with a lot of web development experience, I find it discouraging how difficult custom reports are for me.  So, after struggling to master M2M, I’ve finally given up and started writing simple web-based interfaces to the M2M database.  In the hopes of finding others who might be going down this road, I’m providing &lt;a href=&quot;https://github.com/heedspin/m2mhub&quot;&gt;m2mhub&lt;/a&gt; as open source. Though it is not a turn-key application, I would be interested in collaborating with others to make it more useful.&lt;/p&gt;

&lt;div class=&quot;breakout mod&quot;&gt;
	&lt;h3&gt;The Made2Manage Group on LinkedIn&lt;/h3&gt;
  &lt;p&gt;
		I had earlier created an m2mhub google group to provide a forum for anyone to collaborate. However, I&#39;ve learned that the &lt;a href=&quot;http://www.linkedin.com/groups/Made2Manage-1793953&quot;&gt;Made2Manage group on LinkedIn&lt;/a&gt; has more traffic than anywhere else. With less that 2,000 companies using M2M, the world is not big enough for more than one forum. So please, join the Made2Manage group on linked in.
	&lt;/p&gt;

	&lt;p&gt;
		&lt;a href=&quot;http://www.linkedin.com/groups/Made2Manage-1793953&quot;&gt;http://www.linkedin.com/groups/Made2Manage-1793953&lt;/a&gt;
	&lt;/p&gt;	
&lt;/div&gt;

&lt;h1 id=&quot;m2mhub-overview&quot;&gt;M2MHub Overview&lt;/h1&gt;

&lt;p&gt;At present I have relatively little built. I am not approaching any report in a comprehensive manner. Instead I only write specific interactions that I know will be useful. So, for example, there is no customer search yet. That hasn’t been as important as searching the item master.&lt;/p&gt;

&lt;p&gt;Strangely, the most powerful part of this app is that I made almost everything clickable. That makes dashboard of recent sales orders (or quotes) a great launching point. You can click on the sales order, or the customer. And from either of those pages, you can click on the item. The initial goal is to make all sales information very easily accessible. This is surprisingly difficult in the M2M app itself.&lt;/p&gt;

&lt;p&gt;So here’s what I have so far:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Quotes&lt;/strong&gt; -
This is simple crud around quotes. The index page is sorted in reverse chronological order. Quotes are more useful on the home page (dashboard) and on the customer view.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sales Orders&lt;/strong&gt; -
This is also simple crud around sales orders. Same as quotes, these are more useful in the context of a dashboard or viewing a customer.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Customers&lt;/strong&gt; -
The customer show page is intended to display as much reference information as possible about a single customer. This page should be useful to sales and sales engineers when speaking with a customer. It contains every previous sales order and quote. In particular, having a quick table mapping from customer part number to company-specific part number has been useful to sales engineers.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Items&lt;/strong&gt; -
At this point items page is just a search. It searches by company and vendor part numbers. This has been been useful as a reference for engineers to look up vendor part numbers. It has also been useful for the shipping receiving department to find a company part number when a vendor only includes their own part number in a shipment.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Home Page Dashboard&lt;/strong&gt; -
Right now the home page shows recent sales orders and quotes. This is just the quickest and easiest dashboard I could think of.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;connecting-to-sqlserver&quot;&gt;Connecting to SQLServer&lt;/h3&gt;

&lt;p&gt;The hardest part about any of this is just connecting your Rails app to a SQLServer database.  If you get discouraged, just remember this: “You can DO IT! Victory will be sweet.”  I have a few more details in the m2mhub github readme. But a good starting point is here: &lt;a href=&quot;https://github.com/rails-sqlserver/tiny_tds&quot;&gt;tiny_tds&lt;/a&gt; and &lt;a href=&quot;https://github.com/rails-sqlserver/activerecord-sqlserver-adapter&quot;&gt;activerecord-sqlserver-adapter&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;basic-architecture&quot;&gt;Basic Architecture&lt;/h3&gt;

&lt;p&gt;Our M2M databases run in our building. I believe this is a typical setup for M2M. So I setup a small Ubuntu server behind our firewall and give it a public IP address. Though I’m a big believer in the cloud, I don’t see another way to do this. I feel ok opening up HTTPS access to my Ubuntu box. I would be much more nervous opening up access to our M2M database to some web app in the cloud.&lt;/p&gt;

&lt;h3 id=&quot;future-plans&quot;&gt;Future Plans&lt;/h3&gt;

&lt;p&gt;I’m planning on doing something with RMA’s and integrating with Lighthouseapp.  I’m also planning on doing a custom shipping report. It would be great to have other people writing some custom reports so we could share code. Join me!&lt;/p&gt;

</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Shareable and Secure Notes and Passwords</title>
        
        <link href="http://www.heedspin.com/2011/09/05/shareable-secure-notes-and-passwords.html"/>
        <updated>2011-09-05T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/09/05/shareable-secure-notes-and-passwords</id>
        <content type="html">&lt;p&gt;My wife and I share files via dropbox. I’ve just set us up using &lt;a href=&quot;http://www.arg0.net/encfs&quot;&gt;encfs&lt;/a&gt;, &lt;a href=&quot;http://notational.net/&quot;&gt;Notational Velocity&lt;/a&gt;, and &lt;a href=&quot;dropbox.com&quot;&gt;Dropbox&lt;/a&gt; to keep important files (with passwords etc) both encrypted and easy browse on our macs. I don’t think it will last, and I don’t recommend others try setting this up. But if you must, here’s what I have done.&lt;/p&gt;

&lt;h2 id=&quot;install-encfs&quot;&gt;Install encfs&lt;/h2&gt;

&lt;p&gt;We’re on Snow Leopard and Lion. Installing encfs was not easy. I prefer DMG installs. When I can’t find those, I first try homebrew. Homebrew has a recipe for encfs, but it wasn’t playin. Something about “dyld: Library not loaded: /usr/local/lib/libintl.8.dylib”. I had to fall back to macports.&lt;/p&gt;

&lt;p&gt;sudo port install encfs&lt;/p&gt;

&lt;p&gt;The underlying magic that lets developers play with the macos filesystem is in flux. You’ve got the MacFUSE incumbant, and new Fuse4X and OSXFuse on the scene. I think MacFUSE is end of life. (There are also some alternate builds of macfuse out there). They’re all in various stages of support of OS X Lion. It’s confusing.&lt;/p&gt;

&lt;p&gt;I think the macport of encfs uses Fuse4X. I have some stability issues (below) that I suspect are from Fuse4X. But I’m happy it mostly works.&lt;/p&gt;

&lt;p&gt;Once installed I recommend playing around with encrypted folders by following &lt;a href=&quot;http://www.arg0.net/encfsintro&quot;&gt;encfs’ extended intro&lt;/a&gt;. In the end you’re going to do something like this:&lt;/p&gt;

&lt;p&gt;encfs /Users/myusername/Dropbox/.encrypted /Users/myusername/unencrypted&lt;/p&gt;

&lt;p&gt;If you don’t have a Dropbox folder you’re doomed. You can’t be helped.&lt;/p&gt;

&lt;p&gt;We’re going to tell Notational Velocity to store it’s notes in the unencrypted folder. If you’re confused about how all the encryption works, my suggestion is to just play with it. It’ll make sense when you see it.&lt;/p&gt;

&lt;h2 id=&quot;notational-velocity&quot;&gt;Notational Velocity&lt;/h2&gt;

&lt;p&gt;Notational Velocity is a note taking app. Go to the website and read all about it. Like many others, I use &lt;a href=&quot;http://brettterpstra.com/project/nvalt/&quot;&gt;the nValt fork&lt;/a&gt;. No reason, really. I just follow the cool kids.&lt;/p&gt;

&lt;p&gt;Go install it and play around. Make sure to configure it to store separate txt files that are NOT encrypted. You’ll see what it’s doing pretty quick. When you’re ready to party, configure Notation Velocity to store it’s text files in your unencrypted folder.&lt;/p&gt;

&lt;p&gt;By the by, it’s not documented well, but you can import tab separated files into Notation Velocity. The first column is the title. The remaining columns are the body on a new lines. So if you have a bunch of existing notes you want to import, you can create a .tsv file and do them in one swoop. Or you could just create a bunch of text files and put them in your unencrypted folder.&lt;/p&gt;

&lt;h2 id=&quot;the-bootstrap-challenge&quot;&gt;The Bootstrap Challenge&lt;/h2&gt;

&lt;p&gt;One of the challenges with this whole thing is that you need encfs to mount your unencrypted folder &lt;em&gt;before&lt;/em&gt; Notational Velocity starts up. If NV gets its grubby hands in your unencrypted folder before encfs has started, then NV will create default files and just be confused. And encfs needs its password, so this step may or may not need to be interactive.&lt;/p&gt;

&lt;p&gt;Some folks have tried using a mac os login hook. I played around with launchd LaunchAgents, which are pretty cool. In the end, those approaches scare me. If something is awry with your setup, your login is hosed. You have to take extreme measures to halt the normal login process.&lt;/p&gt;

&lt;p&gt;Instead, I chose to use the greatest technology ever developed by mankind: AppleScript. That’s right. Fear me. I really just wanted to learn a little bit about AppleScript. It’s a horrible language. But it’s working, so whatever.&lt;/p&gt;

&lt;p&gt;All it does is prompt for a password, mount your encrypted folder using encfs, and then launch Notation Velocity (or nValt in my case). All the other code in there is basic error checking to make sure it doesn’t try to mount the folder if it’s already there. I tried to make it fancy with KeyChain, but failed on Lion.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-applescript&quot; data-lang=&quot;applescript&quot;&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;home_directory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;system attribute&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HOME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;encrypted_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;home_directory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Dropbox/.encrypted&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;unencrypted_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;home_directory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/unencrypted&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileExistsAtPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;home_directory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/unencrypted/.mount_verification&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Already Mounted&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExistsAtPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;encrypted_folder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;display dialog&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Can not find Dropbox folder&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExistsAtPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;unencrypted_folder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;display dialog&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Can not find unencrypted folder&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;user_password&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;getPassword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Encrypted Folder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;echo &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;user_password&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; | /opt/local/bin/encfs -S &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;encrypted_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;unencrypted_folder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nvALT&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;activate&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# I originally wanted this to look into keychain before prompting. However, I was&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# only able to get it working on Snow Leopard. Keychain Scripting is gone on Lion.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# The interwebs say to use the security command line. That works, but throws noisy &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# errors if the password isn&#39;t stored there. So in the end, I&#39;m removing support for &lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# keychain. Thanks apple.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;getPassword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;key_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;password_result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;text returned&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;display dialog&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;key_name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; Password&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;answer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;hidden&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;answer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;password_result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#local password_result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# This only works on Mac OS Lion&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# tell application &quot;Keychain Scripting&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#	tell keychain &quot;login.keychain&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#		get {password} of (first key whose name is key_name)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#		set password_result to result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#	end tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# end tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# This works but throws error if not in keychain.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# set password_result to (do shell script &quot;security find-generic-password -ga &#39;Magic Box&#39; 2&amp;gt;&amp;amp;1 &amp;gt; /dev/null | cut -d&#39;\&quot;&#39; -f2&quot;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#on error theErroer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#	set password_result to missing value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#end try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#if (password_result is missing value) then&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#	set password_result to text returned of (display dialog key_name &amp;amp; &quot; Password&quot; default answer &quot;&quot; with hidden answer)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#end if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#return password_result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;getKeychainPassword&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;directoryExistsAtPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- boolean	&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;if [ -d &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;quoted form&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; ] ; then exit 0 ; else exit 1 ; fi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;theError&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;directoryExistsAtPath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Credit: Mikey-San from http://hintsforums.macworld.com/archive/index.php/t-90226.html.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;fileExistsAtPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;-- boolean	&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;if [ -f &quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;quoted form&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; ] ; then exit 0 ; else exit 1 ; fi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;theError&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileExists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;fileExistsAtPath&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I compile this into an Application that I can install on all relevant computers. The first time it’s launched, it prompts for a password and mounts encfs. If you never need it, you don’t waste time mounting it.&lt;/p&gt;

&lt;div class=&quot;breakout mod&quot;&gt;
&lt;h3&gt;Why We Probably Will Not Use It&lt;/h3&gt;

&lt;p&gt;After all this work I&#39;m still not sure if we will use it long term.  There are a couple of drawbacks:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;encfs can hang my mac like it just don&#39;t care.  If I mount an encrypted drive, unmount it, and then try to mount again? Good night. Press and hold the power button. You&#39;re d. u. n. done. Maybe it&#39;s the underlying fuse library. Who knows. But if we find we can not avoid that sequence then I&#39;ll unuinstall it.&lt;/li&gt;
	
	&lt;li&gt;Multiple machines editing the same notes does not work with Notational Velocity.  While running, NV does not deal well with notes changing out from underneath it. If someone else adds a new note, that&#39;s ok. But even just viewing a note will save it. So if I&#39;m viewing a note while my wife is editing it, it&#39;s a race to the finish. Changes will be lost. Maybe you can recover them from a dropbox version. Or maybe we have a &quot;convention&quot; of never editing secure notes. We can only add new versions and delete the old ones. Did you just feel icky? Yeah, me too.&lt;/li&gt;
	
	&lt;li&gt;It&#39;s sad to only use Notational Velocity for secure notes. I like the app so much, I wish I could use it on unencrypted notes. I may eventually point NV at an unencrypted dropbox folder and just use a text editor to manage the secure notes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;h2 id=&quot;questions&quot;&gt;Questions?&lt;/h2&gt;

&lt;p&gt;I know I left out a bunch of details. How to configure Notational Velocity, what’s the .mount_verified file, etc. This post is mostly to commiserate with others feeling the encfs + dropbox pain. If you really want to feel the thunder and you think I can help, feel free to ask questions.&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Archive Email Before Deleting a Google Apps User</title>
        
        <link href="http://www.heedspin.com/2011/08/13/archive-email-before-deleting-google-apps-user.html"/>
        <updated>2011-08-13T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/08/13/archive-email-before-deleting-google-apps-user</id>
        <content type="html">&lt;p&gt;
&lt;a href=&quot;http://lxdinc.com&quot;&gt;We (at lxd)&lt;/a&gt; are using google apps for business.  When someone leaves the company, we&#39;d like to archive all their emails so that we can access them later without paying google $50/year per user. It&#39;s pretty easy with Thunderbird. In short, we just download all the user&#39;s emails and zip up the Thunderbird profile directory.  In long...
&lt;/p&gt;

&lt;h3 id=&quot;change-password-to-archive_usermycompanycom&quot;&gt;Change password to archive_user@mycompany.com&lt;/h3&gt;

&lt;p&gt;This should probably be part of your normal steps after an employee leaves. Since we’re going to archive the emails, we want to just change the password instead of deactivating the account.  &lt;a href=&quot;http://www.google.com/support/a/bin/answer.py?answer=33319&quot;&gt;Google instructions for changing a user’s password&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;rename-and-forward-usermycompanycom&quot;&gt;Rename and Forward user@mycompany.com&lt;/h3&gt;

&lt;p&gt;As a google domain administrator you need to rename user@mycompany.com to something like archive_user@mycompany.com.  &lt;a href=&quot;http://www.google.com/support/a/bin/answer.py?answer=182084&quot;&gt;Google Instructions For Renaming A User&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That’s going to create a nickname/alias for user@mycompany.com.  So scroll down and delete that nickname.  Then go to another user (e.g., new employee) and add an alias for user@mycompany.com.  That way you don’t lose any emails intended for the account you are going to delete.&lt;/p&gt;

&lt;h3 id=&quot;make-sure-popimap-is-enabled&quot;&gt;Make sure POP/IMAP is enabled&lt;/h3&gt;

&lt;p&gt;You need to login to the archive_user@mycompany.com account, go to mail settings, “Forwarding and POP/IMAP”, and make sure that “Enable POP for all mail (even mail that’s already been downloaded)” is set.  &lt;a href=&quot;http://mail.google.com/support/bin/answer.py?answer=13273&quot;&gt;These Google Instructions are pretty close&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;export-all-the-users-emails&quot;&gt;Export all the user’s emails&lt;/h3&gt;

&lt;p&gt;Install a fresh copy of Thunderbird and connect it to archive_user@mycompany.com with your new password.  Thunderbird is pretty easy to setup.  I have confidence that you can do it!&lt;/p&gt;

&lt;p&gt;It’s best to do this in an empty Thunderbird profile.  If you already use Thunderbird, you can &lt;a href=&quot;http://support.mozillamessaging.com/en-US/kb/using-multiple-profiles&quot;&gt;Setup Multiple Profiles in Thunderbird&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you kick off Thunderbird, it will take a long time to download everything.  Just let Thunderbird sit there for many hours.  I leave it overnight.  I don’t really know how to tell when it’s done other than when it just seems to stop downloading more.  :-)&lt;/p&gt;

&lt;h3 id=&quot;zip-up-the-profile-directory&quot;&gt;Zip up the profile directory&lt;/h3&gt;

&lt;p&gt;Exit Thunderbird and &lt;a href=&quot;http://kb.mozillazine.org/Profile_folder_-_Thunderbird&quot;&gt;find your Thunderbird profile directory&lt;/a&gt;.  You can just zip that profile directory and put the zip file on a DVD or where you want to store it permanently.  On the same DVD, it’s a good idea to include installers for the version of Thunderbird you used to export the emails.  I include a windows and mac installer.&lt;/p&gt;

&lt;h3 id=&quot;accessing-archived-emails&quot;&gt;Accessing archived emails&lt;/h3&gt;

&lt;p&gt;Should the day come when you need to go find an old email, it’s pretty easy.  I just install a fresh copy of Thunderbird (from the DVD).  I’ve done this on both Windows and Mac. When it asks to enter an email address, just cancel.  Depending on your operating system, it may complain about a failed install because you cancelled.  Ignore that.  What you just did was create an empty profile.&lt;/p&gt;

&lt;p&gt;Exit Thunderbird, and find that empty profile directory.  Unzip your DVD copy the Thunderbird profile and copy the contents into the new empty profile directory.  Then just start Thunderbird.  All the archived emails should be there in their searchable glory.  I’ve even exported from Windows and opened them from Mac.  Thunderbird’s profile directory seems to be nicely portable.&lt;/p&gt;

&lt;p&gt;BTW, there’s a mozbackup program out there that makes backing up a profile super easy.  But that program does not run on mac, so I vote no.  Just zip up the profile directory.  Sorry mozbackup.&lt;/p&gt;

&lt;h3 id=&quot;delete-the-old-accounts&quot;&gt;Delete the old accounts&lt;/h3&gt;

&lt;p&gt;Before deleting a user I recommend verifying that you have access to the archived emails. Also, you’ll want to &lt;a href=&quot;http://www.google.com/support/a/bin/answer.py?answer=1247799&quot;&gt;transfer ownership of any google docs&lt;/a&gt; and &lt;a href=&quot;http://www.google.com/support/calendar/bin/answer.py?answer=37082&quot;&gt;share calendars&lt;/a&gt;.  Once you delete the archive_user@mycompany.com account, any Thunderbirds will start complaining about failed authentication.  Just go into Thunderbird’s server settings and uncheck everything.  That’ll keep it from trying to connect to an account that doesn’t exist.&lt;/p&gt;

&lt;h3 id=&quot;will-my-archive-work-10-years-from-now&quot;&gt;Will My Archive Work 10 Years From Now?&lt;/h3&gt;

&lt;p&gt;No.  Whatever OS you’re exporting on now will be end of life eventually.  Your archived installers will not work.  And the latest version of Thunderbird will have no idea how to load that profile directory.  This approach is good for a few years.  If you need to guarantee access for many years you should really just keep the google accounts and deactivate them.  Pay the $50/year and thank your lucky clouds.&lt;/p&gt;

&lt;h2 id=&quot;feedback-welcome&quot;&gt;Feedback welcome&lt;/h2&gt;

&lt;p&gt;Let me know if you approach this differently…&lt;/p&gt;

</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Verizon Network Extender Doesn&#39;t Work Until You Activate It With Verizon</title>
        
        <link href="http://www.heedspin.com/2011/08/04/verizon-network-extender.html"/>
        <updated>2011-08-04T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/08/04/verizon-network-extender</id>
        <content type="html">&lt;div class=&quot;breakout mod&quot;&gt;
&lt;h3&gt;Updated August 18th, 2011 after Giametti edumacated me&lt;/h3&gt;
  &lt;p&gt;
		Thanks to Giametti&#39;s comment below, I called Verizon and was able to get this thing working.  The process is awesome.
		&lt;ul&gt;
			&lt;li&gt;You need a Verizon account. I have a wireless account.  Don&#39;t know if another service would do.  Perhaps.&lt;/li&gt;
			&lt;li&gt;Call Customer Support (*611 on your mobile).  I don&#39;t know what option to press.  I just hit 0 to get an operator.&lt;/li&gt;
			&lt;li&gt;Wait on hold and try to keep the on hold music from making you crave brains.&lt;/li&gt;
			&lt;li&gt;Tell them you want to activate a Verizon Network Extender.&lt;/li&gt;
			&lt;li&gt;Guess what happens next? Yup, they transfer you. More on hold music. More brains...&lt;/li&gt;
			&lt;li&gt;You will eventually be connected to someone who has delicious brains.  He/she will actually know what&#39;s up.  You&#39;ll need to read them the mac id on the bottom of the device. He&#39;ll also want it plugged in and ready to go at the time. The GPS actually went blue while I was on the phone with them.&lt;/li&gt;
			&lt;li&gt;It might be a few minutes before the sys light goes blue. Mr Delicious Brains said my box was old and would automatically download a firmware update and reboot.&lt;/li&gt;
			&lt;li&gt;Victory&lt;/li&gt;
		&lt;/ul&gt;
  &lt;/p&gt;
	&lt;p&gt;
		What&#39;s the lesson here?  A red GPS light might just mean you&#39;re not activated yet.  I&#39;m amused at the whole experience, but I&#39;m super happy to be able to &lt;a href=&quot;http://techcrunch.com/2011/08/16/jeremy-and-his-mom/&quot;&gt;call Mom&lt;/a&gt; from home again.
	&lt;/p&gt;
	&lt;p&gt;
		Original whiny post below...
	&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I purchased the Samsung SCS-26UC4 in an attempt to get a Verizon signal at home.  But drats, I just can’t get it to work.  So with this post I cast my vote into the great google expanse.  Boo Verizon.  Boo Samsung.  Your product doesn’t work for me.  Can you hear me now?  No…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/verizon-net-extender/samsung-scs-26uc4-zoom.jpg&quot; width=&quot;630&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;no-gps-signal&quot;&gt;No GPS signal&lt;/h2&gt;

&lt;p&gt;The problem is that my device can’t get a GPS signal.  In short, these network extenders need a GPS signal for 911 calls.  We live in Raleigh, NC.  My droid, iphone, and ipad all know exactly where I am.  The Samsung SCS-26UC4 does not.  I used the external antenna.  Put that thing out every window.  Put it on the roof.  Wrapped it around a tree.  Whispered sweet nothings to it.  No luck.  I even took that blasted box to work (near the airport) and tried there.  Nope.&lt;/p&gt;

&lt;p&gt;So really?  No GPS signal?  I kind of feel like it’s not really trying. So I vote no. The Samsung SCS-26UC4 is a P.O.S..&lt;/p&gt;

&lt;h2 id=&quot;any-ideas-welcome&quot;&gt;Any ideas welcome&lt;/h2&gt;

&lt;p&gt;If you have any ideas on how to get a GPS signal, please let me know…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/verizon-net-extender/samsung-scs-26uc4.jpg&quot; width=&quot;630&quot; /&gt;&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Configuring delayed_job Logging</title>
        
        <link href="http://www.heedspin.com/2011/01/17/delayed-job-logging.html"/>
        <updated>2011-01-17T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/01/17/delayed-job-logging</id>
        <content type="html">&lt;p&gt;I use &lt;a href=&quot;https://github.com/tobi/delayed_job&quot;&gt;delayed_job&lt;/a&gt; to run things when you least expect it!  I want my web request to be logged to RAILS_ROOT/log/production.log and my delayed_job work to be logged to RAILS_ROOT/log/production_delayed_job.log.  Here’s how I configure delayed_job to log to a separate file.&lt;/p&gt;

&lt;h2 id=&quot;rails_rootconfigdelayed_job_configrb&quot;&gt;RAILS_ROOT/config/delayed_job_config.rb&lt;/h2&gt;

&lt;p&gt;I drop this into my RAILS_ROOT/config/delayed_job_config.rb.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Delayed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 
  &lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;BufferedLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;log/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_delayed_jobs.log&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Delayed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;auto_flushing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/.*\/script\/delayed_job:\d+$/&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Delayed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;logger&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The auto_flushing=1 addresses some issue with delayed_job assuming it’s getting a buffered logger.  &lt;a href=&quot;https://github.com/collectiveidea/delayed_job/issues/issue/47&quot;&gt;You can read about it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The caller.last parsing is the hack I put in to get all my application logging into the delayed job log.  delayed_job_config.rb is loaded by your web app as well as by the delayed job processes.  This conditionally hijacks the ActiveRecord::Base.logger if we’re running in the delayed_job daemon.&lt;/p&gt;

&lt;p&gt;An important part of getting this to work is to use ActiveRecord::Base.logger correctly in your models.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyModel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mymethod&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
      This will get written to log/production.log
      when called by a web request, but
      it will be written to log/production_delayed_job.log
      when called in a delayed job.
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;    TEXT&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Always goes to log/production.log&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;questions&quot;&gt;Questions&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Is there a better way to detect that I’m running in the delayed_job daemon?&lt;/li&gt;
  &lt;li&gt;Is there a better logger than the BufferedLogger and auto_flushing=1?&lt;/li&gt;
&lt;/ul&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Setting up monit&#39;s environment to start and stop delayed_job</title>
        
        <link href="http://www.heedspin.com/2011/01/08/setting-up-monit-environment-for-delayed-job.html"/>
        <updated>2011-01-08T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2011/01/08/setting-up-monit-environment-for-delayed-job</id>
        <content type="html">&lt;div class=&quot;breakout mod&quot;&gt;
	&lt;p&gt;Update March 18, 2012:&lt;/p&gt;
	&lt;h3&gt;Using Rails 3?&lt;/h3&gt;
	&lt;p&gt;I&#39;m using Rails 3.1.3.  To get DJ working I&#39;ve had to stick with delayed_job 2.1.4.  The 3.0.1 build results in &quot;undefined method `before_fork&#39; for nil:NilClass&quot;.  If you google around enough you&#39;ll find the reasons why.  If you&#39;re like me and have other things to do, just stick with 2.1.4 for now.&lt;/p&gt;
	&lt;p&gt;Thanks &lt;a href=&quot;http://www.jonathandean.com/2011/08/delayed_job-in-rails-3/&quot;&gt;jonathan dean&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I use &lt;a href=&quot;http://mmonit.com/monit/&quot;&gt;Monit&lt;/a&gt; to keep &lt;a href=&quot;https://github.com/tobi/delayed_job&quot;&gt;delayed_job&lt;/a&gt; running.  Getting monit to start and stop delayed_job is a giant pain, mostly because of environment problems.  In this post I explain how I make it work.&lt;/p&gt;

&lt;h2 id=&quot;monit&quot;&gt;Monit&lt;/h2&gt;

&lt;p&gt;First off, install monit.  It’s pretty easy.  But remember to set startup=1 in /etc/default/monit.  Also, I recommend adding your email as an alert recipient in /etc/monit/monitrc.&lt;/p&gt;

&lt;p&gt;To tell monit how to start and stop delayed_job, I create /etc/monit.d/check_process_delayed_job with the contents below.  Check monit docs for details around my alert and restart settings.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;check process myapp_delayed_job with pidfile /path/to/myapp/tmp/pids/myapp_delayed_job.pid
  start program &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/bin/bash /path/to/myapp/script/monit_delayed_job.sh start&quot;&lt;/span&gt;
    as uid wei and gid wei
  stop program &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;/bin/bash /path/to/myapp/script/monit_delayed_job.sh stop&quot;&lt;/span&gt;
    as uid wei and gid wei
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;cpu &amp;gt; 60% &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;2 cycles &lt;span class=&quot;k&quot;&gt;then &lt;/span&gt;alert
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;cpu &amp;gt; 80% &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;5 cycles &lt;span class=&quot;k&quot;&gt;then &lt;/span&gt;restart
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;totalmem &amp;gt; 200.0 MB &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;5 cycles &lt;span class=&quot;k&quot;&gt;then &lt;/span&gt;restart
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;3 restarts within 5 cycles &lt;span class=&quot;k&quot;&gt;then &lt;/span&gt;timeout
  group background_tasks&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;monit_delayed_jobsh&quot;&gt;monit_delayed_job.sh&lt;/h2&gt;

&lt;p&gt;Notice that it’s starting and stopping delayed_job through an sh script.  My rails_root/script/monit_delayed_job.sh is below.  It does two important things: loading /etc/profile, and logging.  But the greatest of these is logging!&lt;/p&gt;

&lt;p&gt;All the output of monit_delayed_job.sh is logged to log/monit_delayed_job.log, so you can see if you have any environmental errors.  Otherwise monit will swallow the errors and you’ll go mad.  We don’t want that.&lt;/p&gt;

&lt;p&gt;BTW, you can see I’m using bundle exec.  You can easily change the last line of the sh script to start delayed_job however you like.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash                                                                                                                                                  &lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;-lt 1 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; ; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Usage:   &quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &amp;lt;start | stop&amp;gt; &quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;script_location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%/*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt; -P&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$script_location&lt;/span&gt;/..
&lt;span class=&quot;nv&quot;&gt;rails_root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -f &lt;span class=&quot;s2&quot;&gt;&quot;/etc/profile&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
  . /etc/profile
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;logfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$rails_root&lt;/span&gt;/log/monit_delayed_job.log
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-----------------------------------------------&quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&quot;nv&quot;&gt;$logfile&lt;/span&gt; 2&amp;gt;&amp;amp;1
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Running bundle exec ./script/delayed_job &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$action&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&quot;nv&quot;&gt;$logfile&lt;/span&gt; 2&amp;gt;&amp;amp;1
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;date&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&quot;nv&quot;&gt;$logfile&lt;/span&gt; 2&amp;gt;&amp;amp;1
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;env&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&quot;nv&quot;&gt;$logfile&lt;/span&gt; 2&amp;gt;&amp;amp;1

bundle &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; ./script/delayed_job &lt;span class=&quot;nv&quot;&gt;$action&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&quot;nv&quot;&gt;$logfile&lt;/span&gt; 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;etcprofile&quot;&gt;/etc/profile&lt;/h2&gt;

&lt;p&gt;In /etc/profile somewhere I set PATH and RAILS_ENV.  Obviously, you should change these accordingly.  Keeping the path and environment settings in /etc/profile allows me to setup hosts differently.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/sbin:/usr/sbin:/sbin:/usr/local/ruby-enterprise/bin:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;RAILS_ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;production&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;capistrano&quot;&gt;Capistrano&lt;/h2&gt;

&lt;p&gt;I use capistrano to deploy.  My delayed_job.rb recipe is below.  It’s pretty straight forward.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:must_exist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:delayed_job&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Start delayed_job daemon&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:start&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;alert_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Starting delayed job using &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use_monit_for_delayed_job&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;monit&#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;script/worker&#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;use_monit_for_delayed_job&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;monit start &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;monit_service_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cd &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_path&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;amp;&amp;amp; RAILS_ENV=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails_env&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; script/worker start&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Stop delayed_job daemon&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:stop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;alert_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Stopping delayed job using &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use_monit_for_delayed_job&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;monit&#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;script/worker&#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;use_monit_for_delayed_job&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;monit stop &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;monit_service_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;  
        &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cd &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_path&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;amp;&amp;amp; RAILS_ENV=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails_env&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; script/worker stop&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Restart delayed_job daemon&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:restart&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;alert_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Restarting delayed job using &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use_monit_for_delayed_job&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;monit&#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;script/worker&#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;use_monit_for_delayed_job&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;monit restart &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;monit_service_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cd &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_path&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;amp;&amp;amp; RAILS_ENV=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rails_env&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; script/worker restart&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To enable monit in the recipe above, I set these two things in my deploy.rb:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:delayed_job&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:use_monit_for_delayed_job&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:monit_service_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;myapp_delayed_job&#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;logrotate&quot;&gt;Logrotate&lt;/h2&gt;

&lt;p&gt;Rotating logs is fun.  Do it.  Here’s my /etc/logrotate.d/myapp file.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;/path/to/myapp/log/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.log &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  weekly
  missingok
  rotate 100
  compress
  copytruncate
  delaycompress
  sharedscripts
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;victory&quot;&gt;Victory&lt;/h2&gt;

&lt;p&gt;Simple enough, eh?  I hope this helps you get it working.&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>ActiveHash and SuperEnum!</title>
        
        <link href="http://www.heedspin.com/2010/12/26/active-hash.html"/>
        <updated>2010-12-26T00:00:00+00:00</updated>
        <id>www.heedspin.com:/2010/12/26/active-hash</id>
        <content type="html">&lt;p&gt;Jeff Dean’s &lt;a href=&quot;https://github.com/zilkey/active_hash&quot;&gt;ActiveHash&lt;/a&gt; is a great gem for status-type associations.  In this post I show how I extend ActiveHash to improve readability.&lt;/p&gt;

&lt;p&gt;A NewsItem model might belong to Status to indicate values like Published, Draft, and Deleted.  ActiveHash lets you do ActiveRecord type associations, but without having to hit the database.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveHash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveHash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Draft&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Published&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Deleted&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;enum_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# == Schema Information&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Table name: news_items&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  id         :integer(4)      not null, primary key&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  title      :string(255)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  body       :text&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  status_id  :integer(4)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  created_at :datetime&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#  updated_at :datetime&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NewsItem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:status&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:not_deleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
        &lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;news_items.status_id != ?&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                         &lt;span class=&quot;no&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DELETED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;NewsItem is a standard ActiveRecord model, but notice that Status inherits from ActiveHash::Base.  Status will not touch the database, but you can use it like a regular ActiveRecord model.  E.g., in your controllers and models:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;news_item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NewsItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DRAFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;news_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PUBLISHED&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And in your formtastics, you can treat Status like you would an ActiveRecord model:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;  &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In the above examples I’m using the ActiveHash::Enum module to magically add the DRAFT, PUBLISHED, and DELETED enumerations.  Super handy.  However, I have to leave my mark on everything, so I extended ActiveHash a little.  Instead of Status::PUBLISHED, I like to write Status.published.  And I’d also like to be able to easily test the value of a Status instance with shorthand such as @status.published? and @status.deleted?:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;  &lt;span class=&quot;vi&quot;&gt;@news_item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NewsItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NewsItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;draft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@news_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;draft?&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@news_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;published?&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@news_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deleted?&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To do the above I create a little helper module in RAILS_ROOT/lib/active_hash/super_enum:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveHash&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SuperEnum&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;included&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Methods&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loud&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;constant_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@enum_accessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loud&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blank?&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;quiet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loud&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;downcase&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class_eval&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RUBY&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
        def &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quiet&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;?
          self.id == &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loud&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;.id
        end
        class &amp;lt;&amp;lt; self
          def &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quiet&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loud&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
          end
        end
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;        RUBY&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now in my Status module I do this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;active_hash/super_enum&#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveHash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveHash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SuperEnum&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Draft&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Published&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Deleted&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;enum_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Thus in your controllers and models:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;news_item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NewsItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;draft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;news_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;published?&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Functionally, SuperEnum is the same as ActiveHash::Enum.  SuperEnum just shouts a little less for those of us with sensitive eyes.  In any case, you should all be using ActiveHash.  It saves you from writing useless database migrations, db initialization tasks, and it probably saves trees.&lt;/p&gt;

&lt;p&gt;What are other people using for Status-type associations?&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
		
    <entry>
        <title>Transactional Factories</title>
        
        <link href="http://www.heedspin.com/testing/2010/03/22/transactional-factories.html"/>
        <updated>2010-03-22T00:00:00+00:00</updated>
        <id>www.heedspin.com:/testing/2010/03/22/transactional-factories</id>
        <content type="html">&lt;p&gt;Transactional-factories is a ruby gem that I created to help speed up my tests.  It uses nested database transactions to allow efficient, programmatic initialization of test data.  In short, it gives each test case a class-level setup callback that is invoked only once.&lt;/p&gt;

&lt;p&gt;You can see the source code at &lt;a href=&quot;http://github.com/heedspin/transactional-factories&quot;&gt;github.com/heedspin/transactional-factories&lt;/a&gt; and download the gem from &lt;a href=&quot;http://gemcutter.org/gems/transactional-factories&quot;&gt;gemcutter.org/gems/transactional-factories&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;why&quot;&gt;Why?&lt;/h3&gt;

&lt;p&gt;Many of test scenarios require creation of complex test data and are rather difficult to set up.  Here are some requirements for a testing framework:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Complex test data - The framework should allow creation of complex test data.&lt;/li&gt;
  &lt;li&gt;Cleanliness - Tests should clean up after themselves and not leave behind garbage data. (hint: transactions!)&lt;/li&gt;
  &lt;li&gt;Efficiency - Tests should not waste time needlessly recreating test data. (hint: nested transactions!)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;breakout mod&quot;&gt;
&lt;h3&gt;How complex is the test data?&lt;/h3&gt;
  &lt;p&gt;
One of my projects generates state-mandated reports.  For a glimpse into the level of complexity of state reporting requirements, the reader is invited to visit the California Department Of Education site for &lt;a href=&quot;http://www.cde.ca.gov/sp/cd/ci/ccdata.asp&quot;&gt;Child Development Data Reporting&lt;/a&gt;.  This level of detail drives some of our most complicated test cases.
  &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Transactional-factories address complexity, cleanliness, and efficiency using nested transactions and adding class level setup/teardown callbacks.  Here’s how it works: A top level transaction wraps the entire TestCase.  A class-level setup method is called once to allow programmatic creation of test data shared across all tests.  Then each test method is called within a nested transaction that is rolled back to protect the test methods from each other.  The top level transaction is also rolled back to protect the TestCases from each other.  Consider the following test code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;transactional_factories&#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyModelTest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TestCase&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Class method called only once to create test data.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Instance method called before each test method.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert_equal&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete_all&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert_equal&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test_2&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert_equal&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;101&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The sequence of events would be as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Top level transaction begin&lt;/li&gt;
  &lt;li&gt;Class level setup()&lt;/li&gt;
  &lt;li&gt;Nested transaction begin&lt;/li&gt;
  &lt;li&gt;Instance method setup()&lt;/li&gt;
  &lt;li&gt;test_1&lt;/li&gt;
  &lt;li&gt;Nested transaction rollback&lt;/li&gt;
  &lt;li&gt;Nested transaction begin&lt;/li&gt;
  &lt;li&gt;Instance method setup()&lt;/li&gt;
  &lt;li&gt;test_2&lt;/li&gt;
  &lt;li&gt;Nested transaction rollback&lt;/li&gt;
  &lt;li&gt;Top level transaction rollback&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that’s all there is to it.  You get one class level setup to create test data that’s shared across all your tests.  It’s programmatic, so you can use your existing model code to create all your complicated dependencies (addressing complexity).  The transactions keep the test methods and test cases from interfering with each other (addressing cleanliness).  It’s only run once, so you don’t waste time recreating complex data (addressing efficiency).&lt;/p&gt;

&lt;p&gt;Check it out! &lt;a href=&quot;http://github.com/heedspin/transactional-factories&quot;&gt;github.com/heedspin/transactional-factories&lt;/a&gt; and &lt;a href=&quot;http://gemcutter.org/gems/transactional-factories&quot;&gt;gemcutter.org/gems/transactional-factories&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;what-about-activerecord-fixtures&quot;&gt;What about ActiveRecord Fixtures?&lt;/h3&gt;

&lt;p&gt;ActiveRecord fixtures are a clean way to explicitly describe your test data.  And the infrastructure around fixtures in tests is pretty flexible.  With use_transactional_fixtures = false, loading a fixture deletes all data in the respective table, so you get cleanliness that way.  With use_transactional_fixtures = true, you only have to load your fixtures once, and you use transactions to keep each test method from introducing garbage data.  That gives you efficiency and cleanliness.  However, fixtures don’t just address the complexity requirement in my opinion.&lt;/p&gt;

&lt;p&gt;By the way, transactional fixtures are not currently implemented to support nested transactions.  I believe this is just a legacy issue since transactional fixtures came before widespread support for nested transactions (through savepoints).  In any case, transactional fixtures must be disabled in order to use transactional-factories.  I think if transactional fixtures are updated to allow nested transactions, the two can coexist.&lt;/p&gt;

&lt;h3 id=&quot;why-class-level-setup&quot;&gt;Why class-level setup?&lt;/h3&gt;

&lt;p&gt;I decided to make the transactional-factory callback a class-level method to force the programmer to recognize the non-intuitive object semantics of TestCases.&lt;/p&gt;

&lt;p&gt;The way ruby’s Test::Unit::TestCase works is to create a new instance of your test case for each test method.  It’s just a strange thing that probably makes sense to people smarter than me.  So in the MyModelTest example above, two instances of MyModelTest would be created; one for test_1, and another for test_2.  (Extra credit to the person who can explain why there are actually more than 2 instances of MyModelTest created).&lt;/p&gt;

&lt;p&gt;Once consequence of this approach is that test methods can not share instance variables.  You might never notice this if you’ve been using the instance method setup, since it’s called on each instance.  However, since we will only call our transactional-factory setup method once, we have to decide what the scoping should be.  I decided to make it class-level so I wouldn’t be tempted to use instance variables.  Class variables will work just fine.&lt;/p&gt;

&lt;h3 id=&quot;questions&quot;&gt;Questions&lt;/h3&gt;

&lt;p&gt;Is anyone else approaching this differently?  Do any other test frameworks address this?  E.g, spec?&lt;/p&gt;

&lt;p&gt;What are the implications for testing application transactions?&lt;/p&gt;
</content>
        <author>
            <name></name>
            <uri></uri>
        </author>
    </entry>
		
    
</feed>