<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1653089315389588439</id><updated>2011-12-02T07:38:23.330-08:00</updated><category term='ruby'/><category term='seo'/><category term='meta'/><category term='delsolr'/><category term='rails'/><category term='resque-scheduler'/><category term='method_of_the_day'/><category term='render_partials_comments'/><category term='bugs rails'/><category term='github'/><category term='performance'/><category term='api ruby github'/><category term='redis_feature_control'/><title type='text'>The Avvo Developer Blog</title><subtitle type='html'>writing code between lawsuit threats.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-4249512726618170775</id><published>2011-04-11T15:45:00.000-07:00</published><updated>2011-05-02T16:48:56.782-07:00</updated><title type='text'>An Event Apart - Seattle (Day 1, part 2)</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/04/an-event-apart-seattle-day-1-part-2.html"&gt;here&lt;/a&gt;

&lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;a href="http://ruby-on-the-interrails.blogspot.com/2011/04/event-apart-seattle-day-1-part-1.html"&gt;Previously.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Web Typography&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://jasonsantamaria.com/"&gt;Jason Santa Maria&lt;/a&gt;, self-described font geek, gave a talk on fonts in general and the huge opportunities sites like TypeKit give for improving the look and feel of your own sites. As recently as three years ago, we were still stuck using the 18 Web Fonts or hacks like sIFR to get real fonts on websites. Publications like the New Yorker, who are instantly recognizable from the typefaces they use, have had a hard time carrying that brand identity to their websites. Many have resorted to rendering each headline in the correct font into images, creating a maintenance nightmare. With the ability to use things like &lt;code&gt;font-face&lt;/code&gt;, existing publications can carry their brand identity with them to the web, and new publications can enhance their own identity with their font selections. Even simple things like the ability to use condensed fonts on the web has totally changed the way well-designed sites look.&lt;/p&gt;

&lt;h3&gt;How do I choose the right typeface?&lt;/h3&gt;

&lt;p&gt;There is a difference between &lt;em&gt;display typefaces&lt;/em&gt;, which are most useful for headlines and titles, and &lt;em&gt;text typefaces&lt;/em&gt;, which are best for body text. A display typeface like &lt;a href="http://en.wikipedia.org/wiki/Bodoni"&gt;Bodoni&lt;/a&gt; can be great for an article's title, but can be difficult to read in a smaller size. Most people will have the best bet finding a few good fonts with many faces, like &lt;a href="http://en.wikipedia.org/wiki/FF_Meta"&gt;FF Meta&lt;/a&gt; or &lt;a href="http://www.ms-studio.com/FontSales/proximanova.html"&gt;Proxima&lt;/a&gt; that can be used successfully in many different scenarios. Good typography is about building contrast, texture, and feeling on the page that help with comprehension and enjoyment of the thing being read. "Good typography is invisible."&lt;/p&gt;

&lt;p&gt;When using typography, there are a few guidelines that can be useful, but should be broken when appropriate:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;All things being equal, err on the side of the text size being too big&lt;/li&gt;
 &lt;li&gt;Contrast is the most important tenet of good design - make parts of the text that differ in some way &lt;em&gt;look&lt;/em&gt; different. Play with size, weight, coler, etc. to build the right amount of contrast.&lt;/li&gt;
 &lt;li&gt;Line spacing should be directly proportional to the line length and &lt;a href="http://en.wikipedia.org/wiki/Typography#Color"&gt;color&lt;/a&gt; of the font&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are lots of things to consider when picking the right fonts, but there are ways to help choose among them. Noting the qualities you want your site and your content to convey will help you narrow long lists of fonts down. Finding fonts that come in both serif and sans serif faces can make pairing simpler and will help create contrast where it's needed. Fonts that have the same feel as a commonly used font can help you pick similar but more interesting fonts. And finally, trying different fonts out by setting some text in a range of typefaces and playing with them will almost always be really helpful. Jason left us with a few sites that use web typography well: &lt;a href="http://lostworldsfairs.com/"&gt;Lost World's Fairs&lt;/a&gt; and &lt;a href="http://www.voltagefashionamplified.com/"&gt;Voltage: Fashion Amplified&lt;/a&gt;.&lt;/p&gt;


&lt;h2&gt;Why Designers Fail&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.scottberkun.com/blog/"&gt;Scott Berkun&lt;/a&gt; was next, with a talk about design failures and how to learn from them. Mindful practice and studying other people are the two primary ways people learn new things, and studying failure in particular is an incredible untapped resource of knowledge. In the design world, it's difficult to find good analysis of design failures. Especially in fields like architecture, where highly in-demand designers tend to move on to new projects frequently, it's sometimes difficult for these designers to see and hear the feedback that only comes from using the product. How do you avoid falling into common design traps? Understand that all designers fail most of the time (whether it's on the drawing board or in the real world), own the mistakes that you do make, analyze the cause (whether it's setting the wrong goals or failing to meet them), and studying common causes of failure and possible mitigations.&lt;/p&gt;

&lt;p&gt;Scott showed an amazing &lt;a href="http://www.youtube.com/watch?v=uhnV21sL9UI"&gt;video&lt;/a&gt; of designer Matt Wiley laying out a magazine article, and how many intermediate failure states he went through in the process of coming up with a great design. These are the things that many people don't see when they look at a finished product. There's a constant process of experimenting, failing, and revising that is absolutely critical to the creative process, but isn't visible at all in the final product.&lt;/p&gt;

&lt;p&gt;So why do designers fail? Some of it comes from falling into common traps: problem-solving for its own sake (Puzzle traps), obsessively categorizing (Category traps), confusing measurements with reality (Number traps), and loving the sketch more that what it actually represents (Drawing traps). Some of it is related to skill: there's often a mismatch between the skills that designers have and the skills that an organization needs, especially around persuading decision-makers that good ideas are good ideas. Designers should be "ambassadors for good ideas", and that involves knowing how to sell these ideas to decision makers. Luckily, persuasion, like most skills, can be learned, and it is something that designers should take the time to learn.&lt;/p&gt;

&lt;p&gt;Scott did some research to discover which of these failures were the most common and the most important. By far, the biggest overall issue was organizational: "Non-designers making design decisions." Others were psychological: Not seeking enough data before designing, and not being receptive to feedback. Less common and important were skill-related issues, with the top being lack of awareness of business fundamentals, and lack of idea-pitching skills. Scott  &lt;a href="http://bit.ly/failreport"&gt;publicly posted his data&lt;/a&gt;, which is really worth a look, and his slides are &lt;a href="http://bit.ly/failslides"&gt;also available&lt;/a&gt;. Hopefully, being able to identify these causes of failure will help us, as a profession, avoid them in our future work.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-4249512726618170775?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/4249512726618170775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=4249512726618170775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/4249512726618170775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/4249512726618170775'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/04/event-apart-seattle-day-1-part-2.html' title='An Event Apart - Seattle (Day 1, part 2)'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-6133682941700681689</id><published>2011-04-04T14:50:00.000-07:00</published><updated>2011-05-02T16:50:12.682-07:00</updated><title type='text'>An Event Apart - Seattle (Day 1, part 1)</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/04/an-event-apart-seattle-day-1-part-1.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  I went to &lt;a href="http://aneventapart.com/2011/seattle/"&gt;An Event Apart Seattle&lt;/a&gt; last week and it was the best conference I've ever been to. I've started to gather my notes together and will, over the next few posts, talk about what I was able to take away from each of the presentations. Before I go in detail on the talks, though, I wanted to mention a few themes that seemed to flow through multiple presentations during the conference.
&lt;/p&gt;

&lt;h3&gt;HTML5 and CSS3 are ready &lt;strong&gt;now&lt;/strong&gt;.&lt;/h3&gt;

&lt;p&gt;
  This theme was the most related to the work I do on a daily basis. Every talk that touched web development explored features that weren't available in every browser (one talk was &lt;em&gt;built&lt;/em&gt; around them), and it seems that the web design community has finally abandoned the idea that sites should act the same way in every browser. Most of the speakers accepted that sites should still &lt;em&gt;work&lt;/em&gt; in some way in every browser, but it seemed accepted as given that we should start using HTML5 and CSS3 features tastefully to enhance the experience of people using modern browsers (and especially modern &lt;strong&gt;mobile&lt;/strong&gt; browsers).
&lt;/p&gt;

&lt;h3&gt;Context is everything&lt;/h3&gt;

&lt;p&gt;
  Whether it was talking about simplicity as delivering the correct experience to the correct user or pairing the correct font or design or architecture or business goal to the correct content or tailoring a mobile web application to fit the behavior of a user who just wants to get the information they need and get &lt;em&gt;on&lt;/em&gt; with their life, context was brought up constantly. Building the right context for the job you're trying to do involves asking pointed, well-thought-out questions, and several of the presentations had slide after slide of thought-provoking questions intended to bring the assumed context out into the open.
&lt;/p&gt;

&lt;h3&gt;The things we have been talking about as important before, are now critical&lt;/h3&gt;

&lt;p&gt;
  From the data some of the presentations revealed, we are beginning to hit a critical moment in many areas the web touches. Mobile is the most obvious example: Luke Wroblewski was fond of mentioning that smartphone shipments overtook PC shipments a full two years earlier than expected. There were others, too: the rise of HTML5 and CSS3, the ability of sites like TypeKit to drastically help increase your site's branding, and the growth of content strategy as a discipline to deliver the right information to the right people at the right time. These things that were important before are now becoming necessary, because people are beginning to expect great experiences from the sites they visit, and if they can't get it from your site, they will get it somewhere else.
&lt;/p&gt;

&lt;h2&gt;A whirlwind tour of the history of the web&lt;/h2&gt;

&lt;p&gt;
  &lt;a href="http://www.zeldman.com/"&gt;Jeffrey Zeldman&lt;/a&gt; started the conference with a fast and funny history of the web. Beginning with Movable Type (Gutenberg, not Six Apart), passing through AOL, the browser wars, an unfortunately de-pixelated Zeldman on the cover of "Designing with Web Standards", and the fall of XHTML, and finishing up with mobile browsing, HTML5/CSS3, web fonts, and the IE9 beta, it did a fantastic job of setting the context for the rest of the conference. Today, thanks to the widespread adoption of web standards, the web has grown up. We can now make use of skills that were not previously useful online to create a better web experience for everyone. And since the web is now everywhere, those experiences can affect people beyond what was previously possible.
&lt;/p&gt;

&lt;h2&gt;Better user experiences through psychology&lt;/h2&gt;
&lt;p&gt;
  &lt;a href="http://www.sazzy.co.uk/"&gt;Sarah Parmenter&lt;/a&gt; was next, giving a talk called "Crafting User Experiences." Sarah discussed how well-known psychological principles could be used to build great user experiences. I noticed a lot of parallels to one of my favorite recent books, &lt;a href="http://www.amazon.com/Predictably-Irrational-Hidden-Forces-Decisions/dp/006135323X"&gt;Predictably Irrational&lt;/a&gt; (which should be next on your list if you haven't yet had the opportunity to read it), and I found it really interesting that a lot of this knowledge that used to seem to be confined to sales and marketing is now making its way into mainstream web design.
&lt;/p&gt;

&lt;p&gt;
  Snap judgements and sensation transference were the first topics hit. We usually deny that snap judgements are as important as they are, since we tend to thing that "the quality of a decision is directly related to the time and effort that went into making it." In reality, judgements made in under 5 minutes are drastically more important to our final decisions than we realize. This is related to to sensation transference: our judgement of the packaging of a product can have real effects on our perception of the actual product. For example, adding yellow coloring to 7up made people percieve more lime taste while drinking it. This led to the first appearance of the &lt;a href="http://wiki.darkpatterns.org/"&gt;Dark Patterns wiki&lt;/a&gt; during the conference. Like any skill, though, these skills can be used for good as well as evil.
&lt;/p&gt;

&lt;p&gt;
  Better user experiences through psychology can be delivered by concentrating on &lt;b&gt;speed, simplicity, surprise, social proof, and stirring emotions&lt;/b&gt;. Speed involves getting people the product they want quickly without any fuss. From working closely on your site's structure and building great navigation to creating quick video overviews of a service, the faster you can get information to someone, the happier they'll be. This goes hand-in-hand with simplicity. Simplicity is delivering the right content to the right person at the right time, and involves really studying your audience and what context they're in when they visit your site. Simplicity is heavily colored by perception, and this can be used to your advantage&amp;mdash;telling your users it will take 30 seconds to sign up on your site when it actually takes 10 will make your site seem easier to use and will make that user feel smarter and better about themselves.
&lt;/p&gt;

&lt;p&gt;
  Surprise is challenging the expectations of your users in some small way. You can evoke this by using complimentary highlight colors on calls to action, or provoking the user to ask questions they need to click through to answer (what &lt;em&gt;is&lt;/em&gt; that weird old tip for a tiny belly?), or even picking a product or company name that provokes surprise and questions from a user (like Sarah herself did with "You Know Who"). Social proof is as simple as pre-filling a tip jar (so it seems normal to leave money) or public follow/like counts on your site (30 million people and counting apparently &lt;em&gt;love&lt;/em&gt; FarmVille). Finally, Sarah talked about how people are much more likely to make judgments on emotion and only later justify them rationally. Things like using lots of whitespace for luxury items or natural textures for organic items create an emotional attraction that can work beautifully when trying to attract a user to your products. Etsy does a great job of this, as did Apple when creating a "How it's made" for their iPhoto holiday cards. Anthropomorphized icons can also work great for creating an emotional attachment, and can be as easy as adding eyes and a smile to, say, an illustration of a house. There was a ton of great stuff in her talk, and I'm looking forward to trying some of the things she mentioned myself.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-6133682941700681689?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/6133682941700681689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=6133682941700681689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/6133682941700681689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/6133682941700681689'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/04/event-apart-seattle-day-1-part-1.html' title='An Event Apart - Seattle (Day 1, part 1)'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-991058293461467411</id><published>2011-03-09T09:20:00.000-08:00</published><updated>2011-05-02T16:50:47.550-07:00</updated><title type='text'>Shortcut Keys for the HipChat Fluid App</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/03/shortcut-keys-for-the-hipchat-fluid-app.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  As
  I &lt;a href="http://ruby-on-the-interrails.blogspot.com/2011/03/hipchat-without-air.html"&gt;mentioned
  last week&lt;/a&gt;, we've started to
  use &lt;a href="http://www.hipchat.com"&gt;HipChat&lt;/a&gt; for our internal
  chat here at &lt;a href="http://www.avvo.com"&gt;Avvo&lt;/a&gt;. I've decided to
  forego their default AIR app and
  try &lt;a href="http://ruby-on-the-interrails.blogspot.com/2011/03/hipchat-without-air.html"&gt;running
  their web interface through Fluid&lt;/a&gt; to get a more native mac-like
  experience. One of the few things that bothered me about the Fluid
  app was the lack of keyboard controls for accessing and closing the
  tabs for each chat
  room. So &lt;a href="https://github.com/justinweiss/hipchat_shortcut_keys"&gt;I
  added them&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  One of the great things about Fluid is its support for userscripts
  to add functionality to the pages it wraps. I created a userscript
  for the HipChat web interface that adds the following keyboard
  shortcuts:
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Command-W: Closes the current tab (if the tab can be closed)&lt;/li&gt;
  &lt;li&gt;Command-1 through Command-9: Selects the tab at the specified position&lt;/li&gt;
  &lt;li&gt;Command-{ and Command-}: Select the previous tab and next tab, respectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  To install it, when running your HipChat fluid instance, open
  'Preferences', go to the 'Advanced' section and add &lt;code&gt;*.user.js&lt;/code&gt; as a
  pattern. Then, go to 'File', 'Open Location' and paste in the following url:
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://github.com/justinweiss/hipchat_shortcut_keys/raw/master/hipchat_shortcut_keys.user.js&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Install the script when it asks, and you should be good to go.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-991058293461467411?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/991058293461467411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=991058293461467411' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/991058293461467411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/991058293461467411'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/03/shortcut-keys-for-hipchat-fluid-app.html' title='Shortcut Keys for the HipChat Fluid App'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-4230375899983138347</id><published>2011-03-02T16:12:00.000-08:00</published><updated>2011-05-02T16:51:43.825-07:00</updated><title type='text'>HipChat without AIR</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/03/hipchat-without-air.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  We've been
  investigating &lt;a href="http://www.hipchat.com"&gt;HipChat&lt;/a&gt; for
  internal chat lately, and I was a little disappointed that it used
  Adobe AIR on all platforms, instead of providing a native app. To be
  fair, it's the most well-done AIR app this side of Basalmiq, but
  there were still the little inconsistencies that I couldn't help but
  get annoyed by. I'm not going to describe the exact things that
  bothered me here,
  since &lt;a href="http://al3x.net/2011/01/15/user-hostile-platforms.html"&gt;Alex
  Payne does such a great job describing the problems here&lt;/a&gt;, but it
  felt weird enough that I couldn't see myself using the app as often
  as I'd use, say, &lt;a href="http://propaneapp.com/"&gt;Propane&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
  Heading through their support pages to get an idea of how I could
  improve my experience, I noticed that there seemed to be a fair
  amount of support for running the web version of HipChat
  through &lt;a href="http://fluidapp.com/"&gt;Fluid&lt;/a&gt;, which, while not
  as pleasant as a native app, still felt much faster and more native
  on the Mac than the AIR app did. HipChat did an amazing job of
  building support for things like Growl notifications and Dock badge
  notifications into the web interface, and seem to want to make the
  site work as well in Fluid as it does through AIR. Given the
  constraints they've set for themselves, HipChat has done a
  tremendous job of building support for people that would like an
  alternative to AIR.
&lt;/p&gt;

&lt;h2&gt;Accessing HipChat through Fluid&lt;/h2&gt;

&lt;p&gt;
  There were only a few minor gotchas I ran into when creating the
  HipChat Fluid app. First, after downloading and running Fluid, the
  URL should be set to &lt;code&gt;https://www.hipchat.com/chat&lt;/code&gt;. The
  icon can be left as the website favicon, which awesomely still takes
  a full-size icon from HipChat's site, rather than the actual tiny
  favicon the site uses. Once inside the HipChat Fluid app, you'll
  have to adjust the preferences. Under the &lt;code&gt;Advanced&lt;/code&gt;
  category, you'll have to add the
  pattern &lt;code&gt;*hipchat.com/sign_in*&lt;/code&gt;, otherwise you won't be
  able to sign in. Finally, if you want Growl and Dock notifications,
  you have to enable notifications through the AIR app&amp;mdash;HipChat
  doesn't expose that setting in the web app.
&lt;/p&gt;

&lt;p&gt;
  There are some cons to running the web app&amp;mdash;although
  notifications, file drag-and-drop, and most of the other
  functionality works, the web app is missing the file/link dock on
  the right hand side, the tabs are a little flakier, you can't video
  chat, and there's a big "Download App" button that would be much
  more valuable as room for another chat tab. However, the use of
  native Mac OS X controls, the smoother scrolling, Growl support
  (rather than the built-in notifications that show up in the wrong
  place), better integration with the system, and the ability to script
  the site with CSS and JavaScript make the Fluid app the way to go.
&lt;/p&gt;

&lt;p&gt;
  Finally, while I was digging through the JavaScript, I noticed that
  HipChat has what looks like decent support for running it as a
  Chrome app, which might be worth trying if you're not on OS X or
  just prefer Chrome.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-4230375899983138347?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/4230375899983138347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=4230375899983138347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/4230375899983138347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/4230375899983138347'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/03/hipchat-without-air.html' title='HipChat without AIR'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-633067686397242233</id><published>2011-02-23T09:36:00.000-08:00</published><updated>2011-05-02T16:52:30.318-07:00</updated><title type='text'>Deploy only tested code with Jenkins and Ruby</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/02/deploy-only-tested-code-with-jenkins-and-ruby.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  Deploying software builds that don't pass the unit tests is a waste
  of time. It prevents QA from doing their job, it causes delays while
  a fixed build is prepared, and it could even lead to more ops time
  to fix if the broken build breaks something on the machines it's
  being deployed to. If you use
  &lt;a href="http://jenkins-ci.org/"&gt;Jenkins&lt;/a&gt; to run your tests,
  there's a better way. Using the Jenkins API, we can get the last
  revision that passed for a project, and adjust our behavior based on
  that revision number.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/cowboyd/jenkins.rb"&gt;Jenkins.rb&lt;/a&gt; is a
  Ruby wrapper for the Jenkins API. &lt;code&gt;gem install
  jenkins.rb&lt;/code&gt; should give you everything you need. Then, you can
  whip up a quick ruby script:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;require 'jenkins'
require 'fileutils'

Jenkins::Api.setup_base_url(:host =&gt; 'jenkins-host.example.com')

# Pull the project name from the command line
project = ARGV[0]

# Retrieve the last successful build number (123, for example)
successful_build = Jenkins::Api.job(project)["lastSuccessfulBuild"]["number"]

# Retrieve information about the actual build, and grab the last built revision out of it
build_info = Jenkins::Api.get("/job/#{project}/#{successful_build}/api/json")
sha = build_info['actions'].detect {|h| h["lastBuiltRevision"] }["lastBuiltRevision"]["SHA1"]
puts sha
&lt;/code&gt;&lt;/pre&gt;    

&lt;p&gt;
  When this script is run with &lt;code&gt;ruby script.rb
  project-name&lt;/code&gt;, it'll return the most recent revision of
  project-name that passed all the tests, which the build script can
  use by calling &lt;code&gt;git reset --hard &lt;em&gt;number&lt;/em&gt;&lt;/code&gt; or
  something else like that.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-633067686397242233?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/633067686397242233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=633067686397242233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/633067686397242233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/633067686397242233'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/02/deploy-only-tested-code-with-jenkins.html' title='Deploy only tested code with Jenkins and Ruby'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-3114648921150596627</id><published>2011-02-16T09:53:00.000-08:00</published><updated>2011-05-02T16:54:07.862-07:00</updated><title type='text'>Paginating custom objects with will_paginate</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/02/paginating-custom-objects-with-will_paginate.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  &lt;a href="https://github.com/mislav/will_paginate/wiki/"&gt;will_paginate&lt;/a&gt;
  makes pagination easy, and we use it whenever we need to show lots
  of ActiveRecord objects. Once the will_paginate gem is installed, it
  provides a built-in &lt;code&gt;#paginate&lt;/code&gt; method for classes that
  inherit from &lt;code&gt;ActiveRecord::Base&lt;/code&gt;, but we still had our
  own crazy hacked-up pagination for the responses we would get back
  from solr. In the interest of making things more consistent and
  deleting as much code as possible, we thought it'd be a good idea to
  look into getting our solr objects into the will_paginate model.
&lt;/p&gt;

&lt;p&gt;
  This turned out to be much easier than
  expected. The &lt;code&gt;will_paginate&lt;/code&gt; view helper expects an
  instance of &lt;code&gt;WillPaginate::Collection&lt;/code&gt;, which is simple
  enough to initialize. It was as easy as adding the following method
  to our search models:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;def paginated_docs(options = {})
  WillPaginate::Collection.create(options[:page] || 1, options[:per_page] || PER_PAGE) do |pager|
    
    @response = $solr_client.query(self.search_options.merge({
      :offset =&gt; pager.offset,
      :limit =&gt; pager.per_page}))
    
    pager.replace(@response.docs)

    # pager.replace sets total_entries if we're on the
    # last page. Otherwise, we'll just populate it.
    unless pager.total_entries
      pager.total_entries = @response.total
    end
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  As long as a &lt;code&gt;WillPaginate::Collection&lt;/code&gt; is returned,
  will_paginate will do the right thing. Something similar should work
  for using other services that support limit/offset, but don't have
  built-in pagination.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-3114648921150596627?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/3114648921150596627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=3114648921150596627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3114648921150596627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3114648921150596627'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/02/paginating-custom-objects-with.html' title='Paginating custom objects with will_paginate'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-3564356369951105720</id><published>2011-02-09T08:50:00.000-08:00</published><updated>2011-05-02T16:54:36.804-07:00</updated><title type='text'>Bulletproof Asset Hosting and CDNs with Rails</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/02/bulletproof-asset-hosting-and-cdns-with-rails.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  After &lt;a href="/2011/02/speeding-up-your-sites-assets-with.html"&gt;setting
  up a CDN&lt;/a&gt; like CloudFront to quickly serve your Rails site's
  assets worldwide, you'll probably want Rails to actually link to the
  assets through the CDN, instead of locally. Rails makes this easy
  with &lt;code&gt;ActionController::Base.asset_host&lt;/code&gt;. The easiest way
  to use &lt;code&gt;asset_host&lt;/code&gt; is by putting the following code in a
  Rails initializer or production.rb:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;ActionController::Base.asset_host = "assets.example.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  After that, calls like &lt;code&gt;image_tag("logo.png")&lt;/code&gt; will produce
  links like:
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;img alt="Avvo" src="http://assets.example.com/images/logo.png?1297189653" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Going past the basics&lt;/h2&gt;

&lt;p&gt;
  While this will work for very simple cases, more complicated
  scenarios need more code. If you put the above snippet in an
  initializer, you'll have to wrap it in
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;if Rails.env.production?
  ActionController::Base.asset_host = "assets.example.com"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Why would you want to do that when you could stick the code in
  production.rb? For our site, it's because we rely on configuration
  set up in other initializers, which won't be ready by the time
  production.rb runs.
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="http://developer.yahoo.com/yslow/"&gt;YSlow&lt;/a&gt; will tell you
  about the next thing that needs to be done. It turns out that some browsers
  will only open two requests to any given hostname during a web
  request. In order to improve the speed at which a browser can fetch
  assets, you'll need to do something a little more complex with
  &lt;code&gt;asset_host&lt;/code&gt;.
&lt;/p&gt;

&lt;h2&gt;Giving a Proc to asset_host&lt;/h2&gt;

&lt;p&gt;
  Along with taking a
  string, &lt;code&gt;ActionController::Base.asset_host&lt;/code&gt; can also take
  a proc. This gives us more flexibility when generating these
  hosts. We can solve the above problem by using a proc instead of a
  string:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;if Rails.env.production?
  # Source is the asset path as a string, request is a request object
  ActionController::Base.asset_host = Proc.new do |source, request|
    # hosts can also be pulled from a config file for more flexibility
    # or skipping the CDN in staging environments
    hosts = ['http://assets1.example.com', 'http://assets2.example.com']

    # Get a semirandom numeric hash that is consistent for the same source,
    # to make sure that the same asset file always maps to the same asset host
    # (This helps the browser cache these assets)
    hash = source.hash

    # Return a semirandomly selected host from the hosts array
    hosts[hash % hosts.length]
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Dealing with secure pages&lt;/h2&gt;

&lt;p&gt;
  The next thing you'll notice, especially if you don't have SSL
  certificates for your asset hosts, is that you'll start getting
  warnings when accessing resources on secure pages. This can be
  easily fixed by adding another condition to the above proc:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;if Rails.env.production?
  # Source is the asset path as a string, request is a request object
  ActionController::Base.asset_host = Proc.new do |source, request|

    if request.ssl?
      "#{request.protocol}#{request.host_with_port}"
    else
      # hosts can also be pulled from a config file for more flexibility
      # or skipping the CDN in staging environments
      hosts = ['http://assets1.example.com', 'http://assets2.example.com']
      
      # Get a semirandom numeric hash that is consistent for the same source,
      # to make sure that the same asset file always maps to the same asset host
      # (This helps the browser cache these assets)
      hash = source.hash
      
      # Return a semirandomly selected host from the hosts array
      hosts[hash % hosts.length]
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  It also turns out that when referring to assets in ActionMailer, you
  sometimes won't get a request. We need to handle that case, too:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;if Rails.env.production?
  # Source is the asset path as a string, request is a request object
  ActionController::Base.asset_host = Proc.new do |source, request|

    if !request #request == false for emails, apparently
      "http://#{AppSettings.host}"
    elsif request.ssl?
      "#{request.protocol}#{request.host_with_port}"
    else
      # hosts can also be pulled from a config file for more flexibility
      # or skipping the CDN in staging environments
      hosts = ['http://assets1.example.com', 'http://assets2.example.com']
      
      # Get a semirandom numeric hash that is consistent for the same source,
      # to make sure that the same asset file always maps to the same asset host
      # (This helps the browser cache these assets)
      hash = source.hash
      
      # Return a semirandomly selected host from the hosts array
      hosts[hash % hosts.length]
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Dynamic assets&lt;/h2&gt;

&lt;p&gt;
  There also might be 'dynamic assets' that the app might use, like
  captchas, images that are generated on the fly by the server, or
  anything else that's not stored on the filesystem. For these you
  might just want to use your web server instead of the asset server:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;if Rails.env.production?
  # Source is the asset path as a string, request is a request object
  ActionController::Base.asset_host = Proc.new do |source, request|

    # Redirect dynamic assets to the web server
    is_asset = source.match(/images|javascripts|assets|stylesheets/)
    
    if !request #request == false for emails, apparently
      "http://#{AppSettings.host}"
    elsif request.ssl? || !is_asset
      "#{request.protocol}#{request.host_with_port}"
    else
      # hosts can also be pulled from a config file for more flexibility
      # or skipping the CDN in staging environments
      hosts = ['http://assets1.example.com', 'http://assets2.example.com']
      
      # Get a semirandom numeric hash that is consistent for the same source,
      # to make sure that the same asset file always maps to the same asset host
      # (This helps the browser cache these assets)
      hash = source.hash
      
      # Return a semirandomly selected host from the hosts array
      hosts[hash % hosts.length]
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Hardcoding exceptions&lt;/h2&gt;

&lt;p&gt;
  Finally, you might run into some javascript libraries that don't
  like being loaded from a different domain than the page being
  loaded. You can hardcode these to be loaded from the web server
  instead, for the final bit of code:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;if Rails.env.production?
  # Source is the asset path as a string, request is a request object
  ActionController::Base.asset_host = Proc.new do |source, request|

    # Some assets aren't happy being loaded from the assets server :-(
    borked_assets = ['tiny_mce']
    
    # Redirect dynamic assets to the web server
    is_asset = source.match(/images|javascripts|assets|stylesheets/)
    
    if !request #request == false for emails, apparently
      "http://#{AppSettings.host}"
    elsif request.ssl? || !is_asset || borked_assets.any? {|asset| source.match(asset)}
      "#{request.protocol}#{request.host_with_port}"
    else
      # hosts can also be pulled from a config file for more flexibility
      # or skipping the CDN in staging environments
      hosts = ['http://assets1.example.com', 'http://assets2.example.com']
      
      # Get a semirandom numeric hash that is consistent for the same source,
      # to make sure that the same asset file always maps to the same asset host
      # (This helps the browser cache these assets)
      hash = source.hash
      
      # Return a semirandomly selected host from the hosts array
      hosts[hash % hosts.length]
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  This snippet of code should handle pretty much any asset you throw
  at it, and is easily expandable using whatever type of
  environment-specific configuration you use. Give it a try, and let
  me know what you think.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-3564356369951105720?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/3564356369951105720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=3564356369951105720' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3564356369951105720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3564356369951105720'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/02/bulletproof-asset-hosting-and-cdns-with.html' title='Bulletproof Asset Hosting and CDNs with Rails'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-5444735362814171415</id><published>2011-02-04T07:56:00.000-08:00</published><updated>2011-05-02T16:55:07.979-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><title type='text'>Speeding up your site's assets with CloudFront</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/02/speeding-up-your-sites-assets-with-cloudfront.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  As part of one of our regular performance passes on Avvo, we decided
  to give
  Amazon's &lt;a href="http://aws.amazon.com/cloudfront/"&gt;CloudFront&lt;/a&gt;
  service a try to speed up the delivery of our images, css, and
  javascript. CloudFront is the CDN part of Amazon's Web Services
  suite, and as such, it replicates requested data it across Amazon's
  CloudFront servers distributed across the world.
&lt;/p&gt;

&lt;p&gt;
  By default, Amazon requires you to host anything distributed through
  CloudFront using &lt;a href="http://aws.amazon.com/s3"&gt;S3&lt;/a&gt;, and S3
  is the only option available through the web interface when
  configuring CloudFront. At first, this didn't seem like it would be
  an issue, but after trying to push our assets to S3 and hit them
  through CloudFront, we began to notice some problems.
&lt;/p&gt;

&lt;h2&gt;Issues with using S3 as a backing store&lt;/h2&gt;

&lt;p&gt;
  It started with the slowness. Uploading our new assets to S3 on
  every deploy only took about a minute, but even a minute represents
  a significant portion of our total deploy time. Annoying, but still
  acceptable. What was less acceptable was the inablity for CloudFront
  and S3 to respond to clients' &lt;code&gt;Accept-Encoding: gzip&lt;/code&gt;
  headers and automatically return the pre-gzip'd files we
  uploaded. Although there were ways
  to &lt;a href="http://www.alfajango.com/blog/how-to-combine-gzip-plus-cdn-for-fastest-page-loads/"&gt;get
  around&lt;/a&gt; this issue, it was at this point that we decided to try
  Amazon's less-documented and
  less-accessible &lt;a href="http://aws.typepad.com/aws/2010/11/amazon-cloudfront-support-for-custom-origins.html"&gt;Custom
  Origins&lt;/a&gt; feature to tell CloudFront to use our site itself as its
  backing store. This, we hoped, would fix both the speed and gzipping
  issues, as well as be simpler to maintain.
&lt;/p&gt;

&lt;h2&gt;Using Custom Origins&lt;/h2&gt;

&lt;p&gt;
  Custom Origins, although less accessible through Amazon's tools than
  S3 origins, seem to offer a much simpler solution for integrating
  CloudFront for assets that aren't already on S3. Fortunately, a few
  of the third-party Amazon Web Services tools already provide support
  for setting up a CloudFront distribution with Custom Origins. If
  your &lt;a href="http://curl.haxx.se/docs/manpage.html"&gt;curl&lt;/a&gt;-fu is
  better than mine, you can hit their server directly by sending
  &lt;a href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/CreatingDistributions.html"&gt;requests
  documented by Amazon&lt;/a&gt;. I prefer Ruby, though, so I tried out the
  newest version of
  RightScale's &lt;a href="https://github.com/rightscale/right_aws"&gt;right_aws&lt;/a&gt;
  gem.
&lt;/p&gt;

&lt;h2&gt;Installing RightAWS&lt;/h2&gt;
&lt;p&gt;
  &lt;em&gt;(As far as I can tell, the right_aws gem available
  with &lt;code&gt;gem install&lt;/code&gt; doesn't yet support custom
    origins. You can skip this part once it does)&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;Installing the gem was pretty easy using git
  and &lt;a href="http://gembundler.com"&gt;bundler&lt;/a&gt;:
&lt;/p&gt;

&lt;pre class="prettyprint sh"&gt;&lt;code&gt;git clone https://github.com/rightscale/right_aws.git
cd right_aws
bundle install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  Of course, you could also build and install the gem yourself, if you
  prefer.
&lt;/p&gt;

&lt;h2&gt;Setting up your Custom Origin&lt;/h2&gt;

&lt;p&gt;Once right_aws is installed, it's easy to write a script or start
  an &lt;code&gt;irb&lt;/code&gt; session to set up a new CloudFront distribution:
&lt;/p&gt;

&lt;pre class="prettyprint ruby"&gt;&lt;code&gt;require 'right_aws'
acf = RightAws::AcfInterface.new('aws public key', 'aws secret key')
acf.create_distribution(
  :comment =&gt; "My Remote Origin",
  :custom_origin =&gt; {
    :dns_name =&gt; "www.myserver.com",
    :http_port =&gt; 80,
    :https_port =&gt; 443,
    :origin_protocol_policy =&gt; 'match-viewer',
  },
  :enabled =&gt; true
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  The only tricky part of the above is
  the &lt;code&gt;origin_protocol_policy&lt;/code&gt; parameter. This parameter
  can take one of two values, &lt;code&gt;http-only&lt;/code&gt;
  or &lt;code&gt;match-viewer&lt;/code&gt;. This specifies whether https requests
  to CloudFront assets will make https requests to your custom
  origin. Amazon suggests that &lt;code&gt;http-only&lt;/code&gt; should be used
  unless there's a particular reason to use &lt;code&gt;match-viewer&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
  At this point, you should be able to see your new distribution in
  the CloudFront console and hit your assets through the host they
  give you. There's still some more work to do to make sure your
  assets are delivered as quickly as possible, but that's another post
  that'll be written another time.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-5444735362814171415?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/5444735362814171415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=5444735362814171415' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5444735362814171415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5444735362814171415'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/02/speeding-up-your-sites-assets-with.html' title='Speeding up your site&apos;s assets with CloudFront'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-8614265916991642180</id><published>2011-01-28T11:07:00.000-08:00</published><updated>2011-05-02T16:55:53.736-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='api ruby github'/><title type='text'>Introducing the Avvo API</title><content type='html'>Moved &lt;a href="http://code.avvo.com/2011/01/introducing-the-avvo-api.html"&gt;here&lt;/a&gt;

&lt;p&gt;
  As
  we &lt;a href="http://avvoblog.com/2011/01/28/introducing-the-avvo-api/"&gt;announced&lt;/a&gt;
  on the Avvo Blog, we're formally introducing the Avvo API. This
  means that developers can integrate with the data in our
  professional directory in a way that makes sense for their sites and
  applications. The API is RESTful, and returns all responses in JSON,
  so it should be simple to integrate into your own apps.
&lt;/p&gt;

&lt;p&gt;
  For Ruby developers, we went one step further&amp;mdash;we released a
  gem that makes it even simpler to integrate the information on Avvo
  into your own sites and
  applications. The &lt;a href="https://github.com/avvo/avvo_api"&gt;Avvo
  API&lt;/a&gt; gem is available on github and can be installed easily into
  your own apps.
&lt;/p&gt;

&lt;p&gt;
  Installing the gem is as simple as
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem install avvo_api&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  If you use &lt;a href="http://gembundler.com/"&gt;Bundler&lt;/a&gt; in your app,
  you just need to put the following in your Gemfile:
&lt;/p&gt;

&lt;pre class="prettyprint lang-ruby"&gt;&lt;code&gt;source "http://rubygems.org"
gem 'avvo_api', "~&gt;0.1"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  And you should be ready to go. It's easy to get started with the
  API&amp;mdash;all you need is an Avvo account and an API key
  from &lt;a href="mailto:josh@avvo.com"&gt;Josh King&lt;/a&gt;. Here's a short
  example:
&lt;/p&gt;

&lt;pre class="prettyprint lang-ruby"&gt;&lt;code&gt;require 'avvo_api'
AvvoApi.setup('user@avvo.com', 'password')
lawyer_id = AvvoApi::Lawyer.search(:q =&gt; 'tax', :loc =&gt; 'Seattle, WA')["results"].first["id"]

lawyer = AvvoApi::Lawyer.find(lawyer_id)

review = lawyer.reviews.first
puts "#{review.overall_rating} - #{review.title}"    
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  For more documentation and examples, take a look at the Readme
  on &lt;a href="https://github.com/avvo/avvo_api"&gt;github&lt;/a&gt; and the
  rdoc built from the gem. The API gem uses another
  project, &lt;a href="https://github.com/justinweiss/reactive_resource"&gt;Reactive
  Resource&lt;/a&gt;, which you should check out if you're wrapping other
  REST APIs with ActiveResource.
&lt;/p&gt;

&lt;p&gt;
  You can find full documentation and try the API on
  the &lt;a href="http://api.avvo.com"&gt;API documentation site&lt;/a&gt;. We're
  excited to see what you come up with!
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-8614265916991642180?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/8614265916991642180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=8614265916991642180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8614265916991642180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8614265916991642180'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2011/01/introducing-avvo-api.html' title='Introducing the Avvo API'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-8314406304167246245</id><published>2010-12-10T10:42:00.001-08:00</published><updated>2011-05-02T16:56:38.071-07:00</updated><title type='text'>resque-scheduler 2.0.0 pre</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2010/12/resque-scheduler-2-0-0-pre.html"&gt;here&lt;/a&gt;&lt;/p&gt;


I just push resque-scheduler 2.0.0.a.

&lt;pre&gt;
  gem install resque-scheduler --pre
&lt;/pre&gt;

It contains some interesting changes from brianjlandua and davidyang.  The gist of it is, you can now schedule items dynamically.  Here's what it looks like:

Let's say you want your users to configure when some report is generated.  You can do something like this:

&lt;pre&gt;
  Resque.set_schedule('user_16_report', {
    :cron =&gt; "0 1 * * *",
    :queue =&gt; "reports",
    :class =&gt; "GenerateUserReport",
    :args =&gt; 16})
&lt;/pre&gt;

That creates a scheduled job and takes effect immediately.

This is accomplished by storing the schedule state in a redis hash (so, yes, &gt;=1.3 redis is required) and marking changes in an ordered set.  The schedule process looks for changes in the ordered set and then applies them during each loop.  The scheduler tab in resque-web will also pull the schedule from redis, so you can see what's currently scheduled.

This behavior is not default. You need to set this (for the scheduler process and resque-web):

&lt;pre&gt;
  Resque::Scheduler.dynamic = true
&lt;/pre&gt;

By default, resque-scheduler behaves as it always has (other than storing the schedule in redis).  This functionality just opens up new possibilities for scheduling jobs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-8314406304167246245?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/8314406304167246245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=8314406304167246245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8314406304167246245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8314406304167246245'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2010/12/resque-scheduler-200-pre.html' title='resque-scheduler 2.0.0 pre'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-7132106069233597950</id><published>2010-08-07T22:46:00.000-07:00</published><updated>2011-05-02T16:57:28.881-07:00</updated><title type='text'>Ummm.. That's What She Said</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2010/08/ummm-thats-what-she-said.html"&gt;here&lt;/a&gt;&lt;/p&gt;

Ok, so we were joking at work the other day about whipping up a "that's what she said" Bayes classifier.   Someone pointed out that you could use a Twitter search for #twss to train it.  A couple hours later I found my self on the bus coding it up.  

The result is the twss gem.  &lt;a href="http://github.com/bvandenbos/twss"&gt;Check it out on github&lt;/a&gt;.  Usage looks something like this:

&lt;pre&gt;
    requre 'twss'
    TWSS("Have you checked out that file?") # =&gt; false
    TWSS("Yeah... I think it's too big") # =&gt; true
&lt;/pre&gt;

The classifier and twitter gems do all the heavy lifting.  

Yes, I realize this is childish, lowbrow humor, but I just couldn't resist seeing if it would work.  Turns out it works enough to be funny.

Expect an IRC bot soon :)

UPDATE:

IRC bot can be found &lt;a href="http://github.com/bvandenbos/twssbot"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-7132106069233597950?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/7132106069233597950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=7132106069233597950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/7132106069233597950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/7132106069233597950'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2010/08/ummm-thats-what-she-said.html' title='Ummm.. That&apos;s What She Said'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-3031360988376120099</id><published>2010-03-11T09:19:00.000-08:00</published><updated>2011-05-02T16:58:07.322-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resque-scheduler'/><category scheme='http://www.blogger.com/atom/ns#' term='redis_feature_control'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Disabling internal services gracefully with resque, resque-scheduler, and redis_feature_control</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2010/03/disabling-internal-services-gracefully-with-resque-resque-scheduler-and-redis_feature_control.html"&gt;here&lt;/a&gt;&lt;/p&gt;

We've got a data warehouse that is separate from our Rails app's database.  We aggregate data there and then feed summaries back into our Rails app to power all kinds of statistics for our users (impression data, traffic, etc).  We heavily use &lt;a href="http://github.com/defunkt/resque"&gt;Resque&lt;/a&gt; for our backend jobs, including pulling data from our warehouse.  It works great.  A user requests some data, resque serves it up.  It also sends out periodic update emails which include data sourced by our warehouse.

We started running into problems when we wanted to run migrations on our warehouse that took several hours.  Being down during this time is not really acceptable and we didn't want to lose jobs that happened to run and depended on the warehouse being up and in a consistent state.  We needed to be able to tell Resque to stop processing warehouse jobs (but still come back for them later).  We also needed to be able to tell the user that this report was temporarily disabled while we upgraded (rather than timing out).  The rest of the website should continue to run as usual.  

Basically, we needed a central place for processes to look for whether a service (in this case our warehouse) was available.  This switch needed to be able to be turned off programatically (ie: during deployment of a magration) or manually (ie: via an admin tool).  It also needed to be lightweight so even the tiniest script could use it.

We also needed to be able to requeue jobs that needed to wait until the warehouse was back up.  But we didn't want to just requeue them because they would immediately get popped again and could potentially starve lower priority jobs.

We solved the first problem by coming up with &lt;a href="http://github.com/bvandenbos/redis_feature_control"&gt;redis_feature_control&lt;/a&gt;.  Basically, a very simple on/off switch back by redis.  Usage looks like this:

&lt;pre&gt;
  # Check to see if the warehouse is supposed to be up...
  Redis::FeatureControl.enabled?(:warehouse) # =&gt; true

  # Disable the warehouse
  Redis::FeatureControl.disable!(:warehouse)
&lt;/pre&gt;

Pretty simple.

We then wrapped our capistrano task that migrates our warehouse with disable/enable.  We updated our Rails app to display a nice pretty "Please come back in a few minutes" message to our users instantly rather than timing out and detecting errors the hard, ugly way.  And we updated our Resque jobs like so:

&lt;pre&gt;

   def self.perform
     if Redis::FeatureControl.enabled?(:warehouse)
       # do stuff
     else
       # try again in a bit...
     end
   end

&lt;/pre&gt;

Now for the "try again in a bit" part.  This was pretty easy with the &lt;a href="http://github.com/bvandenbos/resque-scheduler"&gt;resque-scheduler&lt;/a&gt; (you can read my previous post on it &lt;a href="http://ruby-on-the-interrails.blogspot.com/2010/01/added-resqueenqueuein-for-delayed.html"&gt;here&lt;/a&gt; and &lt;a href="http://ruby-on-the-interrails.blogspot.com/2009/12/introducing-resque-scheduler.html"&gt;here&lt;/a&gt;).

Basically replace the "try again in a bit" comment with:

&lt;pre&gt;
  Resque.enqueue_in(1.hour, self)
&lt;/pre&gt;

Done.  The job will be pushed back onto the Resque queue in an hour.  If the warehouse still isn't available, it will wait another hour and so on.

End result: When our warehouse is being migrated, it flags itself as being "off" and the dependent processes take the appropriate action, including delaying jobs to be processed in the future.

So far, it's worked like a charm.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-3031360988376120099?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/3031360988376120099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=3031360988376120099' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3031360988376120099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3031360988376120099'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2010/03/disabling-internal-services-gracefully.html' title='Disabling internal services gracefully with resque, resque-scheduler, and redis_feature_control'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-7343837556351735203</id><published>2010-01-11T11:54:00.001-08:00</published><updated>2011-05-02T16:58:45.949-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='resque-scheduler'/><title type='text'>Added Resque.enqueue_in for delayed resque jobs</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2010/01/added-resque-enqueue_in-for-delayed-resque-jobs.html"&gt;here&lt;/a&gt;&lt;/p&gt;

Last week I added support for delayed jobs in resque to the resque-scheduler gem.  You can now do stuff like this:

&lt;pre&gt;
  Resque.enqueue_in(5.days, SendEmailFollowup, :user_id =&gt; current_user.id)
&lt;/pre&gt;

And in 5 days, the job will be queued for work as if you called Resque.enqueue directly.

Alternatively, you can call enqueue_at and pass it a Time instance (or unix timestamp as an int) instead of a number of seconds.

There's also an additional tab in resque-web for viewing delayed jobs.

For screen shots and more details, &lt;a href="http://github.com/bvandenbos/resque-scheduler"&gt;check it out&lt;/a&gt; on github.

If you're interested in calling jobs on a recurring basis, checkout &lt;a href="http://ruby-on-the-interrails.blogspot.com/2009/12/introducing-resque-scheduler.html"&gt;my previous post&lt;/a&gt; on using resque-scheduler to replace cron jobs that just call ruby scripts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-7343837556351735203?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/7343837556351735203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=7343837556351735203' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/7343837556351735203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/7343837556351735203'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2010/01/added-resqueenqueuein-for-delayed.html' title='Added Resque.enqueue_in for delayed resque jobs'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-719247147570364395</id><published>2009-12-21T16:55:00.000-08:00</published><updated>2011-05-02T16:59:36.690-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='resque-scheduler'/><title type='text'>Introducing resque-scheduler</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2009/12/introducing-resque-scheduler.html"&gt;here&lt;/a&gt;&lt;/p&gt;

At Avvo, we've got a lot of backend ruby/rails jobs running as crons.  Jobs to refresh leaderboards, jobs to warm caches, jobs to pull data from third parties.  The list is long and distinguished.  These jobs run on different machines at different times in different intervals.  Up until recently, we've been managing it all with puppet.  We guess at where we have spare cycles to run a job and on which machine.  We've ignored the problem long enough that now we have cron configuration in a couple dozen files running all different sorts of things.  Very annoying and difficult to keep track of.

Just a few weeks ago, we integrated &lt;a href="http://github.com/defunkt/resque"&gt;Resque&lt;/a&gt; and started porting over our jobs.  Having distributed, generic workers is awesome.  It's another thing we've long put off because I couldn't find just the right fit.  Resque is that fit.

Only one thing was missing: A way to add things to queues based on a schedule.

What I wanted in addition to job processing is job scheduling to replace our gagillion cron jobs.

So we hacked up &lt;a href="http://github.com/bvandenbos/resque-scheduler"&gt;resque-scheduler&lt;/a&gt;.

Resque-scheduler is a gem that extends resque to support scheduled jobs.

Installation (hosted on gemcutter.org):

&lt;pre&gt;
  gem install resque-scheduler
&lt;/pre&gt;

Resque-scheduler takes the schedule as a hash, which is easily represented in YAML...

&lt;pre&gt;
queue_documents_for_indexing:
  cron: "0 0 * * *"
  class: QueueDocuments
  args: 
  description: "This job queues all content for indexing in solr

clear_leaderboards_contributors:
  cron: "30 6 * * 1"
  class: ClearLeaderboards
  args: contributors
  description: "This job resets the weekly leaderboard for contributions"

clear_leaderboards_moderator:
  cron: "30 6 * * 1"
  class: ClearLeaderboards
  args: moderators
  description: "This job resets the weekly leaderboard for moderators"

&lt;/pre&gt;

... that can be set in your resque initializer like so:

&lt;pre&gt;
  require 'resque-scheduler'
  ResqueScheduler.schedule = YAML.load_file(File.join(File.dirname(__FILE__), '../resque_schedule.yml'))
&lt;/pre&gt;

Then to run the scheduler process, a simple rake task:

&lt;pre&gt;
  $ rake resque:scheduler
&lt;/pre&gt;

This process idles until a schedule item fires, then it stuffs it into the appropriate queue.

See &lt;a href="http://github.com/bvandenbos/resque-scheduler"&gt;http://github.com/bvandenbos/resque-scheduler&lt;/a&gt; for the complete details.

Obviously, you need to be using resque to take advantage of resque-scheduler

For the future, I'd like to find a clean way to extend resque-web to display the schedule and allow users to click a button to manually queue items in the schedule.

Many thanks to &lt;a href="http://github.com/defunkt/resque")&gt;resque&lt;/a&gt; (defunkt) and &lt;a href="http://github.com/jmettraux/rufus-scheduler/"&gt;rufus-scheduler&lt;/a&gt; (jmettraux) which are doing all the heavy lifting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-719247147570364395?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/719247147570364395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=719247147570364395' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/719247147570364395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/719247147570364395'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2009/12/introducing-resque-scheduler.html' title='Introducing resque-scheduler'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-2034956925994229511</id><published>2009-07-10T09:48:00.001-07:00</published><updated>2011-05-02T17:00:17.056-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Getting ruby, rubygems, rake, mysql, imagemagick, rmagick, aspell, raspell with fink</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2009/07/getting-ruby-rubygems-rake-mysql-imagemagick-rmagick-aspell-raspell-with-fink.html"&gt;here&lt;/a&gt;&lt;/p&gt;

This is really just for me to remember this.  If at some point someone else benefits from this, even better.

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.finkproject.org/download/"&gt;Download and Install fink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Edit /sw/etc/apt/sources.list and add the following:
&lt;pre&gt;
deb http://fink.sodan.ecc.u-tokyo.ac.jp/apt/10.5 unstable main crypto
deb http://sage.ucsc.edu/fink_intel_10.5_only    stable main crypto
deb http://sage.ucsc.edu/fink_intel_10.5_only    unstable main crypto
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Install ruby:
&lt;pre&gt;
sudo apt-get install ruby
sudo apt-get install ruby18-dev
sudo apt-get install ruby18-shlibs
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Install rubygems:
&lt;pre&gt;
sudo apt-get install rubygems-rb18
&lt;/pre&gt;

&lt;li&gt;Update rubygems:
&lt;pre&gt;
sudo gem update --system
sudo gem install rubygems-update # this is to get passed v 1.1.1
sudo update_rubygems
&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;Install rake
&lt;pre&gt;
sudo gem install rake
&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;Then install mysql:
&lt;pre&gt;
sudo apt-get install mysql
sudo apt-get install mysql-client
sudo apt-get install mysql15-dev
sudo gem install mysql
&lt;/pre&gt;
&lt;li&gt;If you want to use a custom my.cnf, plunk it in /etc&lt;/li&gt;
&lt;li&gt;Then install imagemagick and rmagick (this one can be a pain)
&lt;pre&gt;
sudo apt-get install imagemagick10-dev imagemaigck10-shlibs
sudo apt-get install freetype freetype-shlibs ghostscript ghostscript-fonts \
 gv libpng-shlibs libjpeg libjpeg-bin libjpeg-shlibs lcms lcms-bin lcms-shlibs \
 libtiff libtiff-bin libtiff-shlibs
sudo gem install rmagick -v 2.9.2
&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;Install aspell:
&lt;pre&gt;
sudo apt-get install aspell
sudo apt-get install aspell-en
sudo apt-get install apsell-dev
sudo gem install raspell
&lt;/pre&gt;
&lt;/li&gt;

&lt;li&gt;Install other gems:
&lt;pre&gt;
sudo gem install hoe -v 2.0.0
sudo gem install nokogiri
sudo gem install rake-compiler
sudo gem install taka
sudo gem install johnson -v 1.1.0 # 1.1.1 wouldn't install
&lt;/pre&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-2034956925994229511?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/2034956925994229511/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=2034956925994229511' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2034956925994229511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2034956925994229511'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2009/07/getting-mysql-imagemagick-and-other.html' title='Getting ruby, rubygems, rake, mysql, imagemagick, rmagick, aspell, raspell with fink'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-8483830905534196319</id><published>2009-03-16T14:59:00.001-07:00</published><updated>2009-03-16T15:00:02.354-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Introducing cached_attribute - cached values across object instances</title><content type='html'>We've been &lt;a href="http://ryandaigle.com/articles/2008/7/16/what-s-new-in-edge-rails-memoization"&gt;memoizing&lt;/a&gt; attributes manually for a long time, and since we're still on Rails 2.1, we haven't been able to use the nifty new features for memoization. I liked the way Rails 2.2 did it, though, and revisited it when we were investigating some perf issues on the &lt;a href="http://www.avvo.com"&gt;site&lt;/a&gt;.

Memoization is cool and all, but it didn't buy us anything when we had multiple instances of the same object on the same page, so that's where &lt;a href="http://github.com/avvo/cached_attribute/tree/master"&gt;cached_attribute&lt;/a&gt; comes in. Cached_attribute is a plugin that stashes the result of an expensive calculation into a cache, indexed by the object's id. That way, multiple object instances will share the same cached value for the same attribute (on the same object).

The &lt;a href="http://github.com/avvo/cached_attribute/tree/master#readme"&gt;readme&lt;/a&gt; has more information and an example, or you could just check out the code:

&lt;pre&gt;&lt;code&gt;ruby script/plugin install git://github.com/avvo/cached_attribute.git&lt;/code&gt;&lt;/pre&gt;

And as usual, the project is available on &lt;a href="http://github.com/avvo/cached_attribute/tree/master"&gt;github.&lt;/a&gt;

&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-8483830905534196319?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/8483830905534196319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=8483830905534196319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8483830905534196319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8483830905534196319'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2009/03/introducing-cachedattribute-cached.html' title='Introducing cached_attribute - cached values across object instances'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-2996837688758419580</id><published>2009-03-12T15:04:00.000-07:00</published><updated>2009-03-12T15:24:53.695-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Multiple delivery method support for ActionMailer</title><content type='html'>For our test servers (and in development), I wanted to be able to create an action that would display all the emails sent by that mongrel.  When using the :test delivery method, sent emails are readily available in ActionMailer::Base.deliveries. However, for our test server I wanted ActionMailer to send the email with smtp in addition to keeping them around in memory.

So here's the resulting plugin:

&lt;a href="http://github.com/bvandenbos/actionmailer_multiple_delivery_methods/tree/master"&gt;http://github.com/bvandenbos/actionmailer_multiple_delivery_methods/tree/master&lt;/a&gt;

&lt;pre&gt;
ruby script/plugin install git@github.com:bvandenbos/actionmailer_multiple_delivery_methods.git
&lt;/pre&gt;

Then in your development.rb (or environment.rb, or wherever) you can do this:

&lt;pre&gt;
  config.action_mailer.delivery_method = [:test, :smtp]
&lt;/pre&gt;

I've tried it with Rails 2.1.0.  No guarantees with any other version, or even 2.1.0 for that matter ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-2996837688758419580?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/2996837688758419580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=2996837688758419580' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2996837688758419580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2996837688758419580'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2009/03/multiple-delivery-method-support-for.html' title='Multiple delivery method support for ActionMailer'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-5992123461840335489</id><published>2009-01-13T10:59:00.000-08:00</published><updated>2009-03-12T15:25:19.389-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='seo'/><title type='text'>Twitterss - RSS to Twitter script that can handle multiple accounts</title><content type='html'>I know there are a bunch of RSS to Twitter scripts out there in a variety of languages.  There's even &lt;a href="http://twitterfeed.com"&gt;twitterfeed&lt;/a&gt; which manages all your feeds for you (which is a pretty cool service).  But, I couldn't find one that did all of the following:
&lt;ol&gt;
  &lt;li&gt;Took updates as frequently as I wanted&lt;/li&gt;
  &lt;li&gt;Could handle multiple RSS feeds to multiple Twitter accounts (ie: could be configured)&lt;/li&gt;
  &lt;li&gt;Didn't require handing out my Twitter password (not that this is always a bad thing)&lt;/li&gt;
  &lt;li&gt;Didn't have a bunch of dependencies (activerecord, mysqlite, etc...)&lt;/li&gt;
  &lt;li&gt;Preferably written in ruby&lt;/li&gt;
&lt;/ol&gt;
So, I hacked &lt;a href="http://github.com/bvandenbos/twitterss/tree/master"&gt;twitterss&lt;/a&gt; together.

Twitterss is just a script that takes a YAML configuration file as a paramter which is meant to be used as a cron job:
&lt;pre&gt;  $ twitterss twitterss.yml
&lt;/pre&gt;

twitterss.yml might look something like this:
&lt;pre&gt;
legalnews:
  rss: http://www.avvo.com/news.rss
  login: avvolegalnews
  password: secret

cnn_money_top_stories:
  rss: http://rss.cnn.com/rss/money_topstories.rss
  login: money_news
  password: secret
  max: 5

cnn_money_markets:
  rss: http://rss.cnn.com/rss/money_markets.rss
  login: money_news
  password: secret
  max: 3
&lt;/pre&gt;
This config would make twitterss pull items from the &lt;i&gt;CNN Money Top Stories&lt;/i&gt; and the &lt;i&gt;CNN Money Markets&lt;/i&gt; feeds and push them the the &lt;i&gt;money_news&lt;/i&gt; Twitter account.  It would also pull from the &lt;i&gt;Avvo Legal News&lt;/i&gt; feed and push to &lt;i&gt;avvolegalnews&lt;/i&gt;.

Example result:

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_5FTl7AvHPvE/SWzp6EjLVcI/AAAAAAAACFw/u5XLDDk3YIU/s1600-h/Twitter+_+Home.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 62px;" src="http://2.bp.blogspot.com/_5FTl7AvHPvE/SWzp6EjLVcI/AAAAAAAACFw/u5XLDDk3YIU/s400/Twitter+_+Home.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5290860846116459970" /&gt;&lt;/a&gt;

To make sure it doesn't post the same link twice, it keeps a list of each link it posts for each config entry in a local file (&amp;lt;USER_HOME&amp;gt;/.twitterss_history).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-5992123461840335489?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/5992123461840335489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=5992123461840335489' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5992123461840335489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5992123461840335489'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2009/01/twitterss-rss-to-twitter-script-that.html' title='Twitterss - RSS to Twitter script that can handle multiple accounts'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_5FTl7AvHPvE/SWzp6EjLVcI/AAAAAAAACFw/u5XLDDk3YIU/s72-c/Twitter+_+Home.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-295664538508930896</id><published>2008-11-20T13:15:00.000-08:00</published><updated>2008-11-20T13:24:06.981-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='method_of_the_day'/><title type='text'>Method of the Day: index_by</title><content type='html'>Just stumbled on to this one.  I can't tell you how many times I've wanted this functionality.

You have an array, but you want a hash keyed by an attribute of the items in the array. Typically, you'd do something like this:

&lt;pre&gt;users_by_name = {}
users.each { |u| users_by_name[u.name] = u }
&lt;/pre&gt;
Which is of course silliness now that we know about index_by.

&lt;pre&gt;users_by_name = users.index_by(&amp;:name)
&lt;/pre&gt;
Slick.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-295664538508930896?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/295664538508930896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=295664538508930896' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/295664538508930896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/295664538508930896'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/11/method-of-day-indexby.html' title='Method of the Day: index_by'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-8372976333531172879</id><published>2008-11-06T15:32:00.000-08:00</published><updated>2008-11-06T15:36:07.879-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='github'/><category scheme='http://www.blogger.com/atom/ns#' term='meta'/><title type='text'>Pushing to multiple user accounts on GitHub</title><content type='html'>Here at &lt;a href="http://www.avvo.com"&gt;Avvo&lt;/a&gt;, we've started to use &lt;a href="http://www.github.com/avvo"&gt;GitHub&lt;/a&gt; for publishing some of our internal libraries that might be useful to the programming community. Although we have a &lt;a href="http://www.github.com/avvo"&gt;company account&lt;/a&gt;, it's nice to have a &lt;a href="http://www.github.com/justinweiss"&gt;personal account&lt;/a&gt;, too. Unfortunately, github doesn't allow multiple accounts to share the same SSH key. This makes sense, because all communication with github works using the same ssh user account. From my perspective, it can get kind of annoying.

The key to being able to check code into multiple github accounts is setting up multiple ssh keys and using ssh aliases to use the correct key for the correct repo. First, I created a company-specific key:
&lt;pre&gt;&lt;code&gt;justin-mac:~ jweiss$ ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/jweiss/.ssh/id_rsa): /Users/jweiss/.ssh/id_rsa.avvo
Enter passphrase (empty for no passphrase): 
Enter same passphrase again:&lt;/code&gt;&lt;/pre&gt;
Then I set up an SSH alias in &lt;code&gt;~/.ssh/config&lt;/code&gt;:
&lt;pre&gt;&lt;code&gt;host github-avvo
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_rsa.avvo&lt;/code&gt;&lt;/pre&gt;
Next, I copied the &lt;code&gt;id_rsa.avvo.pub&lt;/code&gt; key into the &lt;code&gt;avvo&lt;/code&gt; github acccount.
Finally, when creating the clone of whichever repo I was using, I didn't use the clone path that github gave me, I translated it to use the alias I created. For example, a clone URL like 
&lt;pre&gt;&lt;code&gt;git@github.com:avvo/fuzzy-find-in-project.git&lt;/code&gt;&lt;/pre&gt;
becomes
&lt;pre&gt;&lt;code&gt;github-avvo:avvo/fuzzy-find-in-project.git&lt;/code&gt;&lt;/pre&gt;
Now, when pushing to the central repository, it will pick up the &lt;code&gt;id_rsa.avvo&lt;/code&gt; key that I tied to the &lt;code&gt;avvo&lt;/code&gt; github account, and send the code to the right place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-8372976333531172879?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/8372976333531172879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=8372976333531172879' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8372976333531172879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8372976333531172879'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/11/pushing-to-multiple-user-accounts-on.html' title='Pushing to multiple user accounts on GitHub'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-6028343944799913057</id><published>2008-10-23T14:38:00.001-07:00</published><updated>2008-10-24T08:37:26.075-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='method_of_the_day'/><title type='text'>Method of the Day: Array()</title><content type='html'>Another oldy but a goodie...

Array() wraps its parameter in an array.  If it's already an array, it just returns it.  If it's nil, it returns an empty array.  It's super useful when you want to write a method that can take a single instance of an object or an array of objects.
&lt;pre&gt;
Array(nil) =&amp;gt; []
Array([]) =&amp;gt; []
Array(1) =&amp;gt; [1]
Array([1]) =&amp;gt; [1]

def do_stuff(model_or_models)
  models = Array(model_or_models)
  models.each do |model|
    # do stuff...
  end
end
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-6028343944799913057?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/6028343944799913057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=6028343944799913057' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/6028343944799913057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/6028343944799913057'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/10/method-of-day-array.html' title='Method of the Day: Array()'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-3722059934124717173</id><published>2008-10-22T11:06:00.000-07:00</published><updated>2008-10-22T12:20:31.539-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delsolr'/><title type='text'>DelSolr 0.0.2 Released - Added Support for Updates/Delete</title><content type='html'>A &lt;a href="http://ruby-on-the-interrails.blogspot.com/2008/09/delsolr-solr-facets-made-easy-in-ruby.html"&gt;while ago&lt;/a&gt; I posted on the first version of delsolr (0.0.1) which provided support for querying solr and not much else :).

We just released an update to &lt;a href="http://delsolr.rubyforge.org"&gt;delsolr&lt;/a&gt; (0.0.2).  The major change is added support for updating/deleting documents.  It's still fairly untested, so, standard disclaimer applies.

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;c &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;DelSolr&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Client&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;server&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;solr&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;port&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;8983&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; updating one document...
&lt;/span&gt;doc &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;DelSolr&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Document&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_field&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;id&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;ABC-123&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_field&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;name&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;8 Gig Shuffle&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_field&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;description&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;A crazy-tiny MP3 player&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
c&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;update!&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;doc&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; posts new document to solr
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; updating a whole bunch and batching the post to solr
&lt;/span&gt;models &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;SomeModel&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;find&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;all&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
models&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;model&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  doc &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;DelSolr&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Document&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
  doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_field&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;id&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; model&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;id&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_field&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;name&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; model&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;name&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  doc&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_field&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;description&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; model&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;description&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  c&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;update&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;doc&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
c&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;post_update! &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; post all the updates in one batch
&lt;/span&gt;
c&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;commit! &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; post a commit to solr&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
I used a rails example, but delsolr is really intended for ruby and not necessarily rails.  Acts_as_solr and the like might suit some better (but not us).

This project came out of a piece of code we use internally to manage solr connections.  My goal is to get delsolr to the point where we can replace our old implementation.  It's not there yet, but it's getting closer.  (It's slow going as this is largely done in our "free time".)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-3722059934124717173?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/3722059934124717173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=3722059934124717173' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3722059934124717173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3722059934124717173'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/10/delsolr-002-released-added-support-for.html' title='DelSolr 0.0.2 Released - Added Support for Updates/Delete'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-149846072751523549</id><published>2008-10-14T13:28:00.000-07:00</published><updated>2011-05-02T17:02:00.427-07:00</updated><title type='text'>Introducing fuzzy-find-in-project: TextMate-style file browsing in Emacs</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2008/10/introducing-fuzzy-find-in-project-textmate-style-file-browsing-in-emacs.html"&gt;here&lt;/a&gt;&lt;/p&gt;

I've been trying off and on to learn to use Emacs over the last few months, but I always found myself coming back to TextMate for one reason: the "Command-T" Find File in Project command. I tried a few of the plugins for Emacs that were supposed to replicate the functionality, but none of them had the performance to quickly search through thousands of files. 

I had just about given up when I saw Jamis Buck's &lt;a href="http://weblog.jamisbuck.org/2008/10/10/coming-home-to-vim"&gt;post&lt;/a&gt; about porting an enhanced version of TextMate's functionality to a rubygem, which he could wrap with a vim plugin.

A few days later, I wrote my own wrapper to the gem for Emacs as a way of learning Emacs-Lisp, and posted it to GitHub: &lt;a href="http://github.com/avvo/fuzzy-find-in-project/tree/master"&gt;fuzzy-find-in-project&lt;/a&gt;. It works pretty much like Jamis' vim plugin, and has been pretty fast as far as I can tell (at least, much faster than the pure Elisp plugins I tried). Here's how it works:

&lt;img src="https://justinweiss.s3.amazonaws.com/images/find-file-1.png" /&gt;
&lt;div class="subtitle"&gt;Run the command&lt;/div&gt;

&lt;img src="https://justinweiss.s3.amazonaws.com/images/find-file-2.png" /&gt;
&lt;div class="subtitle"&gt;Narrowing down the possibilities&lt;/div&gt;

&lt;img src="https://justinweiss.s3.amazonaws.com/images/find-file-3.png" /&gt;
&lt;div class="subtitle"&gt;Selecting the next match&lt;/div&gt;

&lt;img src="https://justinweiss.s3.amazonaws.com/images/find-file-4.png" /&gt;
&lt;div class="subtitle"&gt;Opening the matched file&lt;/div&gt;

You can modify the project directory with the function: 

&lt;pre&gt;&lt;code&gt;(fuzzy-find-project-root "~/path/to/project")
&lt;/code&gt;&lt;/pre&gt;

&lt;a href="http://github.com/avvo/fuzzy-find-in-project/tree/master"&gt;Check it out!&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-149846072751523549?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/149846072751523549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=149846072751523549' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/149846072751523549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/149846072751523549'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/10/introducing-fuzzy-find-in-project.html' title='Introducing fuzzy-find-in-project: TextMate-style file browsing in Emacs'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-8184618141377439935</id><published>2008-09-29T15:18:00.000-07:00</published><updated>2008-10-01T10:34:25.673-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs rails'/><title type='text'>Actionview error when naming partials " _next.html.erb"</title><content type='html'>So, today I got this wonderfully cryptic error from the erb compiler:
&lt;pre&gt;
Showing widget/profile_completeness/_next.html.erb where line #52 raised:

compile error
/[path_removed]/_next.html.erb:-3: syntax error, unexpected '=', expecting kEND
next = local_assigns[:next]
     ^
&lt;/pre&gt;
After debugging into action_view, I realized it was because I foolishly named a partial "_next.html.erb".  "next" is apparently some pseudo-reserved word in action_view and if you use it, your template crashes in weird and interesting ways.  I particularly like the negative line number in the error message which results from rails pre-pending code to the erb block when compiling the method used for rendering.

Bug filed &lt;a href="http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1140-partials-named-_next-crash-render"&gt;here&lt;/a&gt;.

&lt;em&gt;
Update: Apparently, you'll run into this if you name your partial any reserved word in ruby (case, class, etc...)
&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-8184618141377439935?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/8184618141377439935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=8184618141377439935' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8184618141377439935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/8184618141377439935'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/actionview-error-when-naming-partials.html' title='Actionview error when naming partials &quot; _next.html.erb&quot;'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-4929170830804827283</id><published>2008-09-23T15:27:00.001-07:00</published><updated>2008-10-23T13:44:06.654-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='render_partials_comments'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Rails hack: Adding html comments to label partials</title><content type='html'>Ever want to figure out which partial a block of html is coming from without greping through your entire rails project?  Render_partial_comments is a rails plugin that renders html comments to mark the begin and end of partial output.  Give it a try:

&lt;pre&gt;
ruby script/plugin install git://github.com/avvo/render_partial_comments.git
&lt;/pre&gt;

Then enable it by adding this global in config/environments/development.rb (or wherever)

&lt;pre&gt;
$render_partial_comments = true
&lt;/pre&gt;

Then restart your server...

Your rendered html will now include html comments wrapping the output from partials.  Should look something like this:

&lt;pre&gt;
&amp;lt;!-- render_begin 'user/view' --&amp;gt;
....
&amp;lt;!-- render_end 'user/view' --&amp;gt;
&lt;/pre&gt;

&lt;em&gt;Update: This may have some adverse effects on autocomplete if you use it&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-4929170830804827283?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/4929170830804827283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=4929170830804827283' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/4929170830804827283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/4929170830804827283'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/rails-hack-adding-html-comments-to.html' title='Rails hack: Adding html comments to label partials'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-7813091941190835013</id><published>2008-09-19T15:42:00.001-07:00</published><updated>2011-05-02T17:03:45.785-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>belongs_to :dependent =&gt; :destroy with foreign key constraints</title><content type='html'>&lt;p&gt;Moved &lt;a href="http://code.avvo.com/2008/09/belongs_to-dependent-destroy-with-foreign-key-constraints.html"&gt;here&lt;/a&gt;&lt;/p&gt;

I discovered what I believe to be a bug in activerecord (2.1.0) today.  If you have something like the following:

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Person&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  belongs_to &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;person_address&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;dependent&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;destroy&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;PersonAddress&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  has_one &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;person&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;

...and you have for foreign key constraint on person_address_id on the person table to id on the person_address table (which would be a reasonable thing to do) you will get a foreign key constraint error when you try to destroy a person record (if the associated person_address record exists).

I submitted a &lt;a href="http://rails.lighthouseapp.com/projects/8994/tickets/1079-belongs_to-dependent-destroy-should-destroy-self-before-assocation#ticket-1079-1"&gt;patch to rails&lt;/a&gt; for this, but in the meantime, I found this as a work around:

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Person&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  belongs_to &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;person_address&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; note: no :dependent =&amp;gt; :destroy
&lt;/span&gt;
  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;destroy&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt;super&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;()&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; first destroy ourselves before we destroy the association
&lt;/span&gt;    &lt;span class="support support_class support_class_ruby"&gt;PersonAddress&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;destroy&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;person_address_id&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;person_address_id
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-7813091941190835013?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/7813091941190835013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=7813091941190835013' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/7813091941190835013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/7813091941190835013'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/belongsto-dependent-destroy-with.html' title='belongs_to :dependent =&gt; :destroy with foreign key constraints'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-5826962026241902914</id><published>2008-09-12T08:26:00.000-07:00</published><updated>2008-09-12T09:34:49.422-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Private Mixins - Including helpers in controllers</title><content type='html'>Despite being fully aware that controllers should include minimal logic, we still have some code that needs to be shared by multiple controllers (and even some views).  The easiest way to share code in ruby is, of course, the mixin module.  The trouble in rails is that any public methods on controllers are exposed as actions, even ones that come in via mixin.  That's trouble.

One solution was to define all methods in our helpers as private.  Didn't really work in every scenario and kind of limits testing.  What we really wanted was to be able to include modules privately.  As far as I can tell, ruby doesn't support this off the shelf, so we decided we give it a shot to see where it took us.

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;
&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Module&lt;/span&gt;&lt;/span&gt;
 
  &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;private&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;protected&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;type&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
    eval &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby string_quoted_double_ruby_mod"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%{&lt;/span&gt;
      def include_&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;type&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;(*prms)
        prms.each do |mod|
          include(mod)
          mod.instance_methods.each do |meth|
            &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;type&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;(meth)
          end
        end
      end
    &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
 
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;
&lt;/pre&gt;

This creates two methods include_private and include_protected.  These guys wrap the normal include method but then take all the instance methods for the included module and privatize or protected-ize them, respectively.

Then we added this to ApplicationController:

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;
&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;ApplicationController&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActionController::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_class meta_class_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;&lt;span class="variable variable_other variable_other_object variable_other_object_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; self&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt;alias_method&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;include_helper&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;include_private&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
 
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;
&lt;/pre&gt;

Now we can include helpers in our controllers privately:

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;
&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;MyController&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ApplicationController&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  include_helper &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;MyHelper&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;
&lt;/pre&gt;

Now, it seems to me that there must be a better way of doing this and we would love to see it because our googling came up empty and it seems odd that we had to resort to this, though it seems to fit our needs just fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-5826962026241902914?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/5826962026241902914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=5826962026241902914' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5826962026241902914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5826962026241902914'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/private-mixins-including-helpers-in.html' title='Private Mixins - Including helpers in controllers'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-238200652915957446</id><published>2008-09-08T13:33:00.000-07:00</published><updated>2008-09-08T14:09:12.530-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='delsolr'/><title type='text'>DelSolr - Solr Facets Made Easy in Ruby</title><content type='html'>&lt;a href="http://delsolr.rubyforge.org"&gt;delsolr - lightweight solr wrapper for ruby&lt;/a&gt;

Here's an example of solr faceting made simple via delsolr:

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="source source_ruby"&gt;c &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;DelSolr&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Client&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;server&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;solr1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;port&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;8983&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; faceting by field...
&lt;/span&gt;rsp &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; c&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;query&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;dismax&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;query&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;mp3 player&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;
                        &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;facets&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;field&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;brand&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;limit&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;5&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;mincount&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; now let's output the facet values and counts
&lt;/span&gt;rsp&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;facet_field_values&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;brand&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;brand&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  puts &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;brand&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt; - &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;rsp&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;facet_field_count&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;brand&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; brand&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; faceting by query... with filtering...
&lt;/span&gt;rsp &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; c&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;query&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;dismax&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;query&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;mp3 player&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;
                        &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;filters&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;onsale&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;
                        &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;facets&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;query&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;instock:true&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;name&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;instock&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;
                                    &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;query&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;price&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;..&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;50&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;description&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;cool&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;name&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;cool_and_cheap&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; 

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; now let's output some query facets
&lt;/span&gt;puts &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Instock: &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;rsp&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;facet_query_count_by_name&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;instock&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
puts &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Sweet: &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;rsp&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;facet_query_count_by_name&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;cool_and_cheap&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;


We've been using this code internally for a bit, so we'd figure we'd open it up as a gem to see if other people find it useful.  There are a number of other gems/plugins that do something similar, but we weren't satisfied with the balance of power and simplicity in any of them, particularly when it comes to faceting.  The full documentation is available on the &lt;a href="http://delsolr.rubyforge.org"&gt;delsolr page&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-238200652915957446?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/238200652915957446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=238200652915957446' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/238200652915957446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/238200652915957446'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/delsolr-solr-facets-made-easy-in-ruby.html' title='DelSolr - Solr Facets Made Easy in Ruby'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-5553961179616232937</id><published>2008-09-03T10:24:00.001-07:00</published><updated>2008-10-23T13:52:12.432-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='method_of_the_day'/><title type='text'>Method of the Day: Array#in_groups_of</title><content type='html'>This one is great for building rows of tables.

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="text text_html text_html_ruby"&gt;&lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;table&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;models&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;in_groups_of&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;3&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;row&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;tr&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; row&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;model&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;td&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="support support_function support_function_actionpack support_function_actionpack_rails"&gt;model&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;td&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;tr&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;table&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;

This will render the array in a left-to-right, top-down order.  If you want to render in top-down, left-to-right order, try this:

  &lt;pre class="textmate-source twilight"&gt;
  &lt;span class="text text_html text_html_ruby"&gt;&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; num_cols &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;3&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;models&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;in_groups_of&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;((&lt;/span&gt;&lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;models&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;length&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;/&lt;/span&gt;num_cols&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;ceil&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;transpose&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;row&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  ...
  &lt;/pre&gt;

That should give you the (more common) column-first layout.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-5553961179616232937?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/5553961179616232937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=5553961179616232937' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5553961179616232937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/5553961179616232937'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/method-of-day-arrayingroupsof.html' title='Method of the Day: Array#in_groups_of'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-2404579762034268768</id><published>2008-09-03T10:19:00.000-07:00</published><updated>2008-10-23T13:52:30.655-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='method_of_the_day'/><title type='text'>Method of the Day: Array#to_sentence</title><content type='html'>An Oldy but a goody...
&lt;pre class="textmate-source twilight"&gt;
&lt;span class="text text_html text_html_ruby"&gt;  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; a &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;hot dogs&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;hamburgers&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;pizza&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  I like &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; a&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_sentence&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;connector&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;and&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;.&lt;/span&gt;
  &lt;/pre&gt;
renders...
&lt;pre&gt;
  I like hot dogs, hamburgers, and pizza.
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-2404579762034268768?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/2404579762034268768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=2404579762034268768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2404579762034268768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2404579762034268768'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/09/method-of-day-arraytosentence.html' title='Method of the Day: Array#to_sentence'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-1098905729208547188</id><published>2008-08-28T09:19:00.000-07:00</published><updated>2008-09-02T11:43:55.629-07:00</updated><title type='text'>InMemoryCacheStore</title><content type='html'>I really like the the acts_as_cached interface for model caching, but there are a few models that we wanted to cache in the process memory, but still maintain expiration functionality.  We came up with this:

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;
&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;InMemoryCacheStore&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&lt;&lt;/span&gt; Hash&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;initialize&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;options&lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;expire_entries&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; options&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;expire_entries&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;set&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;key&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; data&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; ttl &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;expire_entries&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ttl
      &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;key&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Entry&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;data&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;dup&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Time&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;now&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; ttl&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;rescue&lt;/span&gt; data
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;else&lt;/span&gt;
      &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;key&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Entry&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;data&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;dup&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;rescue&lt;/span&gt; data 
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;  &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; If we're expiring entires, first check the expiration and remove it if it's expired
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;  &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; &lt;tt&gt;key&lt;/tt&gt; key
&lt;/span&gt;  &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;get&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;key&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
    r &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;key&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;expire_entries&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby"&gt;&amp;amp;&amp;amp;&lt;/span&gt; r &lt;span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby"&gt;&amp;amp;&amp;amp;&lt;/span&gt; r&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;expires_at &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&lt;&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Time&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;now&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i
      &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;delete&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;key&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
      r &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
    r &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;?&lt;/span&gt; r&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;obj &lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;:&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;private&lt;/span&gt;

&lt;span class="meta meta_class meta_class_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Entry&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;attr_accessor&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;obj&lt;/span&gt;        &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; cached object
&lt;/span&gt;    &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;attr_accessor&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;expires_at&lt;/span&gt; &lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; time in seconds
&lt;/span&gt;
    &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;initialize&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;obj&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; expires_at&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
      &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;obj&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; obj
      &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;expires_at&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; expires_at
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;
&lt;/pre&gt;
Example without expiration:

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;
&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;SomeModel&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  acts_as_cached &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;store&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&gt;&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;InMemoryCacheStore&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;
&lt;/pre&gt;

Example with expiration:

&lt;pre class="textmate-source twilight"&gt;&lt;span class="source source_ruby"&gt;
&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;SomeModel&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  acts_as_cached &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;store&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&gt;&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;InMemoryCacheStore&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;expire_entires&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&gt;&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;self.ttl&lt;/span&gt;&lt;/span&gt;
    &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;24&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;hours
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;
&lt;/pre&gt;

Performance for 1000 lookups:
db on localhost: 1.52 secs
memcached on localhost: 0.78 secs
InMemoryCacheStore: 0.345 secs&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-1098905729208547188?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/1098905729208547188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=1098905729208547188' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/1098905729208547188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/1098905729208547188'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/08/inmemorycachestore.html' title='InMemoryCacheStore'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-2102891486922640316</id><published>2008-08-22T17:28:00.001-07:00</published><updated>2008-09-02T12:11:31.743-07:00</updated><title type='text'>Populating fixtures from a database table</title><content type='html'>One problem with the &lt;code&gt;add_symbolic_names&lt;/code&gt; code posted earlier on the blog is the need to keep the test fixtures in sync with the data in the production database &amp;#8212; otherwise, code can reference constants that exist in production, and will break while running tests.

Keeping these in sync is annoying enough that I wrote a rake task to dump the contents of a table to the appropriate fixtures file. I ended up with something like this:

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="source source_ruby"&gt;      desc &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Overwrite a fixture file with the contents of a table (set by TABLE=)&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
      task &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;generate_from_table&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do 
&lt;/span&gt;        &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;establish_connection&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
        table_name &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;TABLE&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;
        &lt;span class="support support_class support_class_ruby"&gt;File&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;open&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;test/fixtures/&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;table_name&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;.yml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;w&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;file&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
          data &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;connection&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select_all&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;SELECT * FROM &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;table_name&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
          rows &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{}&lt;/span&gt;
          
          data&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;record&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
            rows&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;table_name&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;_&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;record&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;id&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; record
          &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
          
          file&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;write rows&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_yaml
        &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;

Running this rake task will generate a fixture file containing all the information in the table specified by the environment variable &lt;code&gt;TABLE&lt;/code&gt;. In the future, we&amp;#8217;ll probably look at automating the fixture generation for these symbolic tables so we don&amp;#8217;t have to worry about failing tests when we add new rows.

UPDATE: I realized that in most cases, the symbolic name of the database row makes a much better fixture title than the id, which results in the following code: 

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="source source_ruby"&gt;      desc &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Overwrite a fixture file with the contents of a table (set by TABLE=)&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
      task &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;generate_from_table&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do 
&lt;/span&gt;        &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;establish_connection&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
        table_name &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;TABLE&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;
        &lt;span class="support support_class support_class_ruby"&gt;File&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;open&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;test/fixtures/&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;table_name&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;.yml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;w&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;file&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
          data &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;connection&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select_all&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;SELECT * FROM &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;table_name&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
          rows &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{}&lt;/span&gt;
          
          data&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;record&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
            fixture_name &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; record&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;symbolic_name&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;blank? &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;?&lt;/span&gt; 
              &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;table_name&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;_&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;record&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;id&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;:&lt;/span&gt; 
              record&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;symbolic_name&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;downcase
            rows&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;fixture_name&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; record
          &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
          
          file&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;write rows&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_yaml
        &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;
      &lt;/pre&gt;


This gives us nice fixtures that look like this: 

&lt;pre class="textmate-source twilight"&gt;
&lt;span class="source source_yaml"&gt;&lt;span class="keyword keyword_operator keyword_operator_symbol"&gt;---&lt;/span&gt; 
&lt;span class="meta meta_tag meta_tag_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;dog&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt; 
&lt;/span&gt;  &lt;span class="string string_unquoted string_unquoted_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;name&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_unquoted string_unquoted_yaml"&gt;Dog&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_tag meta_tag_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_yaml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_yaml"&gt;"&lt;/span&gt;1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_yaml"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="string string_unquoted string_unquoted_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;symbolic_name&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_unquoted string_unquoted_yaml"&gt;DOG&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_tag meta_tag_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;cat&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt; 
&lt;/span&gt;  &lt;span class="string string_unquoted string_unquoted_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;name&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_unquoted string_unquoted_yaml"&gt;Cat&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_tag meta_tag_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt; &lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_yaml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_yaml"&gt;"&lt;/span&gt;2&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_yaml"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="string string_unquoted string_unquoted_yaml"&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_yaml"&gt;symbolic_name&lt;span class="punctuation punctuation_separator punctuation_separator_key-value punctuation_separator_key-value_yaml"&gt;:&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_unquoted string_unquoted_yaml"&gt;CAT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-2102891486922640316?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/2102891486922640316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=2102891486922640316' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2102891486922640316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2102891486922640316'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/08/populating-fixtures-from-database-table.html' title='Populating fixtures from a database table'/><author><name>Justin Weiss</name><uri>http://www.blogger.com/profile/10946757861528424337</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-3448688182452316876</id><published>2008-08-22T15:29:00.000-07:00</published><updated>2008-08-22T17:07:43.130-07:00</updated><title type='text'>Fixnum to Models</title><content type='html'>I saw &lt;a href="http://andand.rubyforge.org/"&gt;andand &lt;/a&gt;a while back and lol'ed at how clever and awesome it was.  With that in mind, we added a couple methods to Fixnum to clean up record fetching on our more popular models:

&lt;pre class="prettyprint"&gt;
Fixnum.class_eval do

  def to_user
    User.find(self)
  end

end
&lt;/pre&gt;
That way when I find myself with something that might be a user id...

&lt;pre class="prettyprint"&gt;
puts user_id.andand.to_user.andand.name
&lt;/pre&gt;

Maybe not something you'd want on every model, probably not optimized, but hey... it beats checking for nil, looking up the user id, checking for nil again and printing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-3448688182452316876?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/3448688182452316876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=3448688182452316876' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3448688182452316876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/3448688182452316876'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/08/fixnum-to-models.html' title='Fixnum to Models'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-1016070581619475455</id><published>2008-04-02T14:15:00.001-07:00</published><updated>2008-04-02T14:19:56.789-07:00</updated><title type='text'>What do you get when you cross...</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_5FTl7AvHPvE/R_P3kJuKpaI/AAAAAAAAAks/sghb64LSjnA/s1600-h/yak.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_5FTl7AvHPvE/R_P3kJuKpaI/AAAAAAAAAks/sghb64LSjnA/s200/yak.jpg" alt="" id="BLOGGER_PHOTO_ID_5184759796490479010" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;+&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_5FTl7AvHPvE/R_P3qpuKpbI/AAAAAAAAAk0/i13yuSmVTJE/s1600-h/camel.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_5FTl7AvHPvE/R_P3qpuKpbI/AAAAAAAAAk0/i13yuSmVTJE/s200/camel.jpg" alt="" id="BLOGGER_PHOTO_ID_5184759908159628722" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;=&lt;br /&gt;&lt;br /&gt;YAML.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-1016070581619475455?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/1016070581619475455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=1016070581619475455' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/1016070581619475455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/1016070581619475455'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/04/what-do-you-get-when-you-cross.html' title='What do you get when you cross...'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_5FTl7AvHPvE/R_P3kJuKpaI/AAAAAAAAAks/sghb64LSjnA/s72-c/yak.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1653089315389588439.post-2040624482325636770</id><published>2008-02-28T09:07:00.001-08:00</published><updated>2008-08-22T17:09:23.982-07:00</updated><title type='text'>AddSymbolicNames - Making constants out of records in static tables with ActiveRecord</title><content type='html'>Here's the problem:
You've got a fairly complex database schema and you find yourself creating a lot of normalized tables. Then you find yourself writing application code that switches on the values of a normalized table. Then you find your application loading activerecord model after activerecord model to do comparisons. Then you think you need to build an in memory cache to save on lookups.

Here's my quick solution that has worked for me in many situations:

Say you have the following:
&lt;pre class="prettyprint"&gt;
class State &amp;lt; ActiveRecord::Base
  has_many :cities
end

class City &amp;lt; ActiveRecord::Base
  belongs_to :state
end
&lt;/pre&gt;
(Assume State has a code column which stores the two letter state code: 'WA', 'CA', etc)

Now somewhere in your application you want to write some code that only runs for cities in WA. You might have something like the following:
&lt;pre class="prettyprint"&gt;
if city.state.code == 'WA'
# do something
end
&lt;/pre&gt;
So, activerecord is going to end up hitting the database for the state attribute so it can compare the code of that state to 'WA'. Now to avoid the database lookup to fetch the state model, you could of course use any number of caching mechanisms that exist (acts_as_cached, CachedModel). But it might be nice for something like state that doesn't ever change to be able to treat it more like a symbol and less like a model. So you could do something like this:
&lt;pre  class="prettyprint"&gt;
if city.state.code == State::WA
&lt;/pre&gt;
or even better
&lt;pre  class="prettyprint"&gt;
if city.state_id == State::WA
&lt;/pre&gt;
This last one avoids the lookup for state altogether and removes the string constant which could contain typos or change over time.

Now, I deal with a bunch of these types of tables (static content except during new releases, &amp;lt;1000 records, lots of application logic around specific values), so I wrote this simple helper to generate namespaced symbols mapping a column to the id.
&lt;pre class="prettyprint"&gt;
module AddSymbolicNames

  module ClassMethods
    
    def add_symbolic_names(opts = {})
      symbolic_name_attr = opts[:symbolic_name_attrib] || :symbolic_name
      value_attr = opts[:value_attrib] || :id
      
      find(:all).each do |r|
       class_eval %{
        if !defined? #{r.send(symbolic_name_attr)}
         #{r.send(symbolic_name_attr)} =
         #{r.send(value_attr)}
        end
       }
      end
    end
    
  end
  
  def self.included(base)
    base.extend(ClassMethods)
  end
  
end

ActiveRecord::Base.class_eval do 
  include AddSymbolicNames
end
&lt;/pre&gt;
Now with our previous example we can do this:
&lt;pre class="prettyprint"&gt;
class State &amp;lt; ActiveRecord::Base
  has_many :cities
  add_symbolic_names :symbolic_name_attrib =&gt; :code
end

# somewhere in app-land
if city.state_id == State::WA
  # do some awesome washington specific logic
end
&lt;/pre&gt;
This creates symbols for every state that you have in the db (ie, State::WA, State::CA) that map to the id for that record. A few obvious restrictions: the :symbolic_name_attrib column must be unique and it also must not contain whitespace since it will become a symbol.

It's basically like creating enums in c++ that reflect database values but that are set at run time.

You could also do this if you felt like it:

&lt;pre class="prettyprint"&gt;
class State &amp;lt; ActiveRecord::Base
  has_many :cities
  add_symbolic_names :symbolic_name_attrib =&gt; :code,
                     :value_attrib =&gt; :name
end
&lt;/pre&gt;

Now the constant State::WA will return the string "Washington" assuming the 'name' attribute of State returns the name of the state.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1653089315389588439-2040624482325636770?l=ruby-on-the-interrails.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruby-on-the-interrails.blogspot.com/feeds/2040624482325636770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1653089315389588439&amp;postID=2040624482325636770' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2040624482325636770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1653089315389588439/posts/default/2040624482325636770'/><link rel='alternate' type='text/html' href='http://ruby-on-the-interrails.blogspot.com/2008/02/addsymbolicnames-making-constants-out.html' title='AddSymbolicNames - Making constants out of records in static tables with ActiveRecord'/><author><name>Ben</name><uri>http://www.blogger.com/profile/02932517953717081378</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://3.bp.blogspot.com/-XYaRjaG9yZY/TZn57ufhNDI/AAAAAAAADTU/WCw_VFCHazs/s220/IMG_2681-1.png'/></author><thr:total>0</thr:total></entry></feed>
