Posts tagged with: "ruby"

August 23, 2010

bundler ruby gems

Fixing Common Bundler Problems

Mini

by Jerry Cheung

When bundler first came out, I really wanted to like it. It promised a clean way to declare dependencies for your application in a single and definitive place, regardless of what kind of box your app was running on. Unfortunately, bundler has not lived up to the hype, and I've had plenty of headaches from bundler problems. Read on for a list of tips I've pulled together to save you some headache.

Ensure your local bundler is the same version as your server

Different versions of bundler may act differently:

bundle --version  # on your local machine and your server
sudo gem install bundler --version="0.9.26"

Explicitly specify gem versions

Did you know in HTTParty 0.4.5, there is no 'parsed_response' method on a response object? Well, neither did I when it worked fine on my local laptop (0.6.1), but not on the server (0.4.5)

gem "httparty"  # bad times if your system gem is out of date...
gem "httparty", "~> 0.6.1"  # better, but...
gem "httparty", "0.6.1"     # ...why not just specify the version everyone should use?

Check that you are actually using gems installed by bundler

Once in a while, bundler will report success on install, but you'll get the wrong gems loaded in your load path. Grep your load path to double check libraries you're having trouble with:

# in script/console
>> $:.grep /http/
=> ["/Users/jch/.bundle/ruby/1.8/gems/httparty-0.6.1/lib"]

Gemfile conditionals

bundler allows you to specify groups so only gems you need in one environment are loaded:

# we don't call the group :test because we don't want them auto-required
group :test do
  gem 'database_cleaner', '~> 0.5.0'
  gem 'rspec'
  gem 'rspec-rails', '~> 1.3.2', :require => 'spec/rails'
end

All gems you specify in your Gemfile WILL be installed regardless of what RAILS_ENV you're currently on. There's a very deceptively named option called --without that does not work as you would expect:

# weird, but this will install gems in group test
bundle install --without=test

This can turn out to be a disaster if your linux production environment tries to install a OSX specific gem with native extensions that you use for development. An ugly fix in the meantime is to add conditionals that look for an environment variable:

if ['test', 'cucumber'].include?(ENV['RAILS_ENV'])
  group :test do
    # your gems
  end
end

Update your capistrano

Don't forget to bundle when you deploy:

after  "deploy:update_code", "deploy:bundle"
namespace :deploy do
  desc "Freeze dependencies"
  task :bundle, :roles => :app do
    run "cd #{release_path} && bundle install --relock --without=test"
  end
end

NameErrors and autoloading issues

For some gems, bundler will not autoload properly. If you start getting NameErrors or LoadErrors for a gem, read this issue. The fix is to skip the require in your Gemfile and manually do the require in your environment.rb:

# Gemfile
gem 'misbehaving_gem', :require_as => []

# environment.rb
Rails::Initializer.run do |config|
  # ...
  config.gem 'misbehaving_gem'
  # ...
end

Nuke .bundle

When all else fails, and you've pulled out what precious little hair you have left:

rm -rf RAILS_ROOT/.bundle      # removes gems for this project
rm -rf ~/.bundle               # removes cached gems for your current user
rm -rf RAILS_ROOT/Gemfile.lock # lets you do a fresh 'bundle install'

# do a fresh bundle install
bundle install

Other

Bundler is in its infancy, and it continues to get better with each release, so many of these issues might not exist in the near future. In the meantime, I hope this list will save you some time with bundler related headaches. Let me know in the comments if you've encountered other tips for resolving these problems.

Comment | 

Intridea at Lonestar Ruby Conference

Mini

by Renae Bair

For the third straight year in a row, senior-level Intrideans will be at the Lonestar Ruby Conference, on Thursday, August 26th, teaching students about Ruby. Students attending the Ruby Intrigue class will work with our Director of Mobile Development, Brendan Lim, our Director of Development, Adam Bair, and our Director of Research and Development, Pradeep Elankumaran.

In a small class setting, students will work on writing a web crawler, an Asteroids clone, and an SMS server. The instructors will also discuss coding practices and methodologies along the way. In keeping with tradition, we have three instructors to ensure a laid-back and collaborative atmosphere. Students will walk away with three different hand-crafted applications, an overwhelming feeling of accomplishment, and a spiffy t-shirt designed by our creative mastermind, David Potsiadlo.

Lonestar Ruby Conference is part of the Lonestar Ruby Foundation, which aims to educate the public about the Ruby Language. The conference, held in Austin, Texas, is in its fourth year and continues to boast a strong lineup of presenters and teachers. This year's lineup includes Blake Mizerany, the creator of Sinatra, Tom Preston-Wernor, co-founder of Github, Gregg Pollack, James Edward Gray II, and many other prominent members of our community.

Registration is still open for the conference and for the Ruby Intrigue class. If you're local to the area, or if you want to spend some time learning about Ruby in the "live music capital of the world", be sure to sign up today!

Comment | 

A To-Go Plate of Ruby Midwest

Mini

by Michael Bleigh

This past weekend Rubyists from all over descended upon Kansas City (my hometown and new place of residence) for the Ruby Midwest conference. Headlined with keynotes from Chris Wanstrath (of GitHub fame) and Yehuda Katz (of Merb and now Rails fame), more than 150 Rubyists attended the single-track conference at the UMKC campus. Intridea was represented by four members, one talk, and by sponsoring a Kansas City Barbecue dinner for the first night of the conference.

Photo courtesy of peterpunk777’s Flickr stream of the event.

The OMGWTFBBQ ran smoothly overall and gave more than 120 of the attendees a chance to taste some of the best of Kansas City Barbecue from Jack Stack. In addition to some belt-loosening food, we held some lightning talks that included a particularly memorable talk by Jeremy Evans about “Singleton Classes of Singleton Classes.”

My talk focused on the emerging standards for automatic web app interoperation via the OStatus protocol (and through it the PubSubHubbub, Webfinger, Salmon, and ActivityStreams protocols). While the talk was high level, hopefully I sparked some interest in the attendees in learning more about these standards and possibly implementing them in their own applications in the near future.

We had a great time at the event and, judging from Intridea’s TweetSentiments Analysis, a lot of other people had a great time too.

Comment | 

Stop The Hate: Obj-C Deserves Your Love

Mini

by Sean Soper

My first foray into Objective-C was, for lack of a better description, a sink-or-swim situation. I was working for a previous employer and our lead iPhone developer had just been laid off; my old boss was in my office the next day asking me how quickly I could "get up to speed". "You know Ruby", he said, "How difficult could it be?" It was time to get some books.

The first point I would like to raise is that Objective-C, while itself quite elegant (at least in comparison to its namesake), is fairly useless on the Mac platform without the Cocoa framework. And it is this framework that I think a lot of Rubyists get hung up on. The other big sticking point is manual memory management through the use of retain and release.

Cocoa's roots start all the way back in the 1980s with the NeXTSTEP operating system which tagged along with Steve Jobs when he was tapped to lead Apple again in 1996. This is why Cocoa's core classes, such as NSArray and NSString, all begin with 'NS'. The naming scheme is a holdover from that earlier OS and while those two extra characters may not seem like much hassle, to a Rubyist they represent an unnecessary burden of verbosity. In addition, Cocoa makes extensive use of the delegate pattern, something that is rarely seen or needed in Ruby and can make it difficult to trace an execution path for those unfamiliar with the concept. One of the limitations of Objective-C, the inability to create difficulty in creating a function with a variable length argument list, is commonly resolved through the use of the poorly named hash userInfo, which frequently appears in method definitions without any connotation as to its purpose. And lest we forget those wonderfully verbose method names, I think even the most die-hard and grizzled veteran of Objective-C would agree that NSString's stringByReplacingOccurrencesOfString, could have been better-named.

Rubyists are proud of that fact that they don't have to worry about memory management. The more knowledgeable Rubyists could tell you that the garbage collector, or GC, works by continually scanning objects in memory once a process has accumulated eight megabytes worth, checking to see if there are any pointers to those objects and then releasing them back to the OS if they do not. But most Rubyists would refuse to venture any farther down that dark path of memory management out of a simple need to retain their sanity. Indeed, for a good few weeks I struggled with this concept until my fellow iPhone student Paul Barry introduced me to a book that would change my outlook. Titled "Learn Objective-C on the Mac", it proved to be a treasure trove of information on object allocation. Specifically, chapter nine, which dealt with memory management, made it crystal clear what was going on underneath the hood when an object was created, and thus retained, and when it was released. The concept itself is simple: retaining an object increases its "retain count" by one; releasing it reduces that count; and when it reaches zero that space in memory is released back to the OS. Immediately the seemingly-random crashes my applications faced were decipherable and easily fixed while my hostility to Objective-C and the Cocoa framework melted away.

As Rubyists, we tend to value the simple over the complex and prefer not to sweat the small stuff. Yet on a whole we also desire learning new concepts and many of us can attest to that being the driving factor behind leaving a former language of choice behind. On occasion, such as with Objective-C and Cocoa, our preference for simplicity and our desire to learn collide, head-on. But rather than tweet about how ugly Cocoa looks or how memory management in Objective-C is beneath you, I challenge you to dive further. After all, Ruby itself is built on Objective-C's forebear, C, and no programmer has walked away worse for wear after peeking under the hood. Learning Objective-C not only opens up the world of iOS application development but also makes us better Rubyists.

Comment | 

April 28, 2010

ruby opinion

The Future's Pretty Cool, or Why I Love Ruby

Mini

by Michael Bleigh

There have been tons of comparisons between Ruby and other languages (mostly Python) ranging from the technical to the epically titled. I’ve always felt that both languages are nice, but feel much more at home with the expressive, readable Ruby syntax. And don’t get me wrong, I love Ruby for all kinds of language reasons. Re-openable classes, blocks and the general meta-programming DNA of Ruby make it just wonderfully powerful and useful for me as a developer. However, when I think about it the language is really only half the story when it comes to why I love being a Ruby developer.

XKCD The Future's Pretty Cool

Whether it’s inherent in the makeup of the language and those to whom it appeals or the “buck the mainstream” attitude of Rails’s opinionated-ness, Rubyists tend to take to new things like fish to water. An outsider may look at the insane progression of testing frameworks and other different-ways-to-do-the-same-thing and think it’s a kind of madness, sickness, or chaos. Well, I suppose it is. However, living inside the Ruby hurricane has helped me to grow as a developer more than I could possibly have imagined in the few years I’ve been doing it full time. Thanks to Ruby, I was on board with these technologies months or even years before I feel I otherwise would have been (just a few examples):

  • Test-Driven Development: Already a mainstay in the Ruby community when I joined it, TDD has seen some pretty rapid expansion into other languages and communities. I’m not saying Ruby was the first or only, but it was certainly an early and strong TDD community.
  • Distributed Version Control: GitHub is the future not only of project version control but of open-source collaboration. SourceForge by comparison seems like a lumbering dinosaur. Fork, fix, push.
  • NoSQL: I was playing with CouchDB about a year ago, not realizing that soon it would be a player in the biggest developer flamewar since Vim vs. Emacs.

I’m not trying to say that X language doesn’t promote innovation or adoption of new ideas or Y has an inferior community. This isn’t a comparison post. I just know that when it comes to new technologies, most Rubyists I know are already jumping out of the plane while still trying to figure out how the parachute works. That sounds like an insult, but I think it’s amazing. We have a community of people so excited about technology that they literally can’t wait to build on it or for it, and share it with others. The huge proliferation of regional Ruby conferences speaks to this: we’re a group of people so intensely interested in learning about what’s new that we can’t manage holding just a few mainstream conferences each year.

For me, being a part of the Ruby community feels like getting a sneak peek at where software development is going six months to two years from now. That’s not to say it’s all rainbows and daisies…the constantly changing landscape requires a real passionate dedication to keep up or you’ll quickly fall behind, and not all technologies are meant to immediately be deployed to massive-scale production environments (restraint is a skill a good Rubyist must learn and exercise on a regular basis). But I love Ruby because I feel confident that I will be made aware of trends in software development long before I would otherwise be expected to understand them.

It’s fun to live in the future.

Comment | 

April 20, 2010

rack ruby middleware

Rack Middleware and Rack Applications: What's the Difference?

Mini

by Michael Bleigh

Rack is the common Ruby web infrastructure powering just about every framework known to Ruby-kind (Rails, Sinatra and many more). Rack Middleware are a way to implement a pipelined development process for web applications. They can do anything from managing user sessions to caching, authentication, or just about anything else. But one thing that confused me for a long time: what’s the difference between a Rack application and Rack middleware? Both are ostensibly the same, something that responds to #call(env), so how are they different? Unlike Rack applications, Rack middleware have knowledge of other Rack applications. Let’s take a look at what this means with a few simple examples.

The simplest Rack application (in class instead of lambda form) would be something like this:

class RackApp
  def call(env)
    [200, {'Content-Type' => 'text/plain'}, ["Hello world!"]]
  end
end

Note that because the method required by the Rack specification is call and (by no coincidence) this is how you execute Procs and lambdas in Ruby, the same thing can be written like so:

lambda{|env| [200, {'Content-Type' => 'text/plain'}, ["Hello world!"]]}

This hello world app would simply output “Hello world!” from any URL on the server that was running it. While this is obviously simple, you can build entire powerful frameworks around it so long as in the end a request boils down to a status, some headers, and a response body. But what if we want to filter the request? What if we want to add some headers before the main application gets it, or perhaps translate the response into pig latin after the fact? We have no way to say “before this” or “after that” in a Rack application. Enter middleware:

class RackMiddleware
  def initialize(app)
    @app = app
  end
  
  def call(env)
    # Make the app always think the URL is /pwned
    env['PATH_INFO'] = '/pwned'
    @app.call(env)
  end
end

See the difference? It’s simple: a Rack middleware has an initializer that takes another Rack application. This way, it can perform actions before, after, or around the Rack application because it has access to it during the call-time. That’s why this works in a config.ru file:

run lambda{|env| [200, {'Content-Type' => 'text/plain'}, ["Hello world!"]]}

But this does not:

use lambda{|env| [200, {'Content-Type' => 'text/plain'}, ["Hello world!"]]}

Because the ‘use’ keyword indicates a Middleware that should be instantiated at call-time with the arguments provided and then called, while ‘run’ simply calls an already existing instance of a Rack application.

This is something that can be quite confusing, especially if you’re new to the Rack protocol, so hopefully this clears it up a bit!

Comment | 

April 19, 2010

ruby quick tip

Ruby Quick Tip: Instant Utility Modules

Mini

by Michael Bleigh

Sometimes you want to write a batch of utility methods that can be accessed from a module for example Utility.parse_something(string) or any number of useful little tools for your application. Here’s a very clean-looking way to achieve it:

module Utilities
  extend self

  def parse_something(string)
    # do stuff here
  end

  def other_utility_method(number, string)
    # do some more stuff
  end
end

By placing "extend self" at the top of the module, you are telling it to include all of the methods defined on your module as class methods on…your module. Which means that you can now access them like other class methods! While there are other ways to do this, I think this is a very semantically clean way that gets it done quite nicely.

Update: And this is exactly why I post these Quick Tips, because sometimes there’s another solution that I hadn’t heard of! Using Ruby’s module_function you can achieve the same effect:

module Utilities
  module_function
  
  def parse_something(string)
    # do stuff here
  end

  def other_utility_method(number, string)
    # do some more stuff
  end
end

The module_function method either takes multiple symbols as arguments for the methods to turn into module methods or, if invoked without arguments, will cause all subsequent methods to be defined as module functions. You can read the Ruby documentation about it here. Ultimately I’m not sure which I’d go with, as module_function is pretty esoteric (I’ve never come across it in code that I’ve read), but so is extend self. It’s your call, developers!

Comment | 

Persistence Smoothie: Blending NoSQL and SQL at Confoo

Mini

by Michael Bleigh

Earlier this month Pradeep and I had the opportunity to fly to Montreal to speak at Confoo, a multi-disciplinary web technology conference that grew out of a PHP conference. One of the days had a Ruby track and I had the opportunity to present a talk entitled Persistence Smoothie: Blending SQL and NoSQL. While the sessions weren’t recorded, I’ve taken up the practice of screencasting my talks to be able to provide some semblance of a recording afterwards:

The slides are also available on SlideShare for perusal:

I had a great time at the conference and got to speak to some others who were using NoSQL systems in the real world. Montreal was a lot of fun (getting to eat foie gras at Pied de Cochon certainly didn’t hurt) and I’m looking forward to giving a refined version of the same talk at RubyNation 2010

Update: I forgot to include a link to the source code for the application demoed during the talk. Here it is on GitHub.

Comment | 

March 29, 2010

talks ruby

Shanghai On Rails event in China

Mini

by Dingding Ye

The seventh local Ruby event by the Shanghai On Rails community was held last weekend. Our senior engineer, Guoning Lv is the founder of the event and I was there speaking. Thanks to 5173, for providing the space, resources and support. Thanks to everyone who attended, friends both old and new. The passion and energy of the community members made the event a big success. The Chinese Ruby and Ruby on Rails community is growing!

All of the topics at the event were presented by Senior Engineers from professional Rails companies. The presentations were interesting and high-quality. The first topic was about JS2/JSAPI by Factual. JS2 language is a cross-browser object oriented approach to JavaScript which makes JavaScript development more fun and productive.

The second talk was titled “When ERP Fell In Love With Rails”, by Jason from Nanjing RoRedu. He shared his experience about how to manage projects, and teams in their ERP projects.

I gave my talk on NoSQL, titled NoSQL: Re-Think the World, which compared traditional RDBMs with the new storage approach of NoSQL. I also spoke about how to choose between the appropriate method for individual situations.

The final talk was Static Code Analysis For Ruby, given by Richard Huang from Ekohe. He shared his gem, rails_best_practices and talked about its implementation. This a great gem to use in refactoring projects and it is widely used by the open source community.

We had a great time at the event. Thanks again to 5173 for sponsoring the event!

Comment | 

Ruby Quick Tip: Regular Expressions in Case Statements

Mini

by Michael Bleigh

Did you know that you can use regular expressions in case statements in Ruby to check for a match? For instance, if I’m implementing some method_missing functionality and I want to check for bang or question methods, I might be tempted to do something like this:

def method_missing(name, *args)
  name = name.to_s
  if name.match(/!$/)
    puts "Bang Method!"
  elsif name.match(/\?$/)
    puts "Query Method?"
  else
    super
  end
end

But it’d be much cleaner if instead it looked like this:

def method_missing(name, *args)
  case name.to_s
    when /!$/
      puts "Bang Method!"
    when /\?$/
      puts "Query Method?"
    else
      super
  end
end

This is great, but now what if we want to call out a method for bang and question methods? Thankfully Ruby has us covered there as well:

def method_missing(name, *args)
  case name.to_s
    when /^(.*)!$/
      bang_method($1)
    when /^(.*)\?$/
      question_method($1)
    else
      super
  end
end

By using the $1 global variable we can access the last regular expression match performed by ruby. This is just one of those little details that makes working with Ruby such a joy.

Comment | 

March 24, 2010

rubyconfindia talks ruby

Looking Back at RubyConf India 2010

Mini

by Brendan Lim

The first ever RubyConf India took place in Bangalore, India at the Royal Orchid Hotel last weekend. Our Director of Research & Development, Pradeep Elankumaran, and I were there speaking. The event was put together by ThoughtWorks and was unlike any other tech conference we've ever attended. It wasn't the talks, the speakers, or the format -- it was the overall attitude of everybody who attended RubyConf India 2010 that made it very special to us. Everybody who attended were extremely passionate about learning and showed so much interest in all of the topics that were presented for the two days of the conference.

 

All of the topics presented at RubyConf India 2010 were interesting. Roy Singham, Founder and Chairman of ThoughtWorks, kicked off and closed the event. Ola Bini of ThoughtWorks gave a talk on "The Future of Programming Languages". Nick Sieger from Engine Yard was there to give his talk on "Rails 3 Through Choices". The highlight of the two-day event was when Yukihiro "Matz" Matsumoto, the father of Ruby, gave a talk via Skype about the future of Ruby. He also mentioned that work on Ruby 2.0 would start in August of this year. There were also talks by Nick Sieger, Arun Gupta, Aman King, Brian Guthrie, and many others. You can see the whole list of speakers and talks by going here.

 

Our very own Pradeep Elankumaran gave two talks. His first talk was titled "The Big Wave of Indian Startups - (Almost) Effortless Entrepreneurship", which sparked a large amount of audience participation and was one of the most interactive sessions of the weekend. His other talk was "Messaging Queueing in Ruby - An Overview", which went over different choices we could use to do queueing in Ruby. I gave my talk on MacRuby, titled "MacRuby to The Max", which went over MacRuby, HotCocoa and how it compared to Objective-C. I even did some live coding and created a quick and easy currency converter.

We had a great time at the first ever RubyConf India. We definitely want to thank ThoughtWorks for putting together a great conference that was extremely informative and enjoyable. You can bet that we'll be there again for RubyConf India 2011.

Comment | 

Hashie Gains a Chainable Hash

Mini

by Michael Bleigh

Hashie, Intridea’s Hash Toolkit, is today with version 0.2.0 gaining a new member: the Clash.

A Clash is a “Chainable Lazy Hash” that allows you to construct a hash using method syntax. It is meant to be used in a similar way to the way that Rails 2.x’s named_scope or Arel’s query building work. Let’s start with an example:

require 'hashie/clash'

c = Hashie::Clash.new
c.where(:abc => 'def').order(:created_at)

c == {:where => {:abc => 'def'}, :order => :created_at}

Pretty neat, right? But you can go beyond that. Clash also allows you to use bang method notation to create, dive into, and return from sub-hashes. Let me show you what I mean:

c = Hashie::Clash.new
c.where!.abc('def').ghi(123)._end!.order(:created_at)

c == {:where => {:abc => 'def', :ghi => 123}, :order => :created_at}

By using a bang method, you automatically create a subhash that is then the subject of the chain, allowing you to create more keys on that subhash. Then, if you want to jump back up to the top-level hash, you simply call the _end! method to return up one level in the stack (thanks to jQuery for that particular inspiration).

While Clash is a very simple tool, we hope that it could eventually make its way into some of the new ORMs that are cropping up around NoSQL systems (such as MongoMapper) to provide the same kind of effortless chaining that has made ActiveRecord so easy to work with.

Comment | 

Redfinger: A Ruby WebFinger Gem

Mini

by Michael Bleigh

Just yesterday, Google turned on webfinger for all GMail accounts. Today, we’re releasing a RubyGem to help you use the new protocol!

What’s a WebFinger?

WebFinger is a new protocol for extracting public information about a person via their e-mail address. It is meant to complement systems such as OpenID as well as give a simple way to get basic information about a user without having to ask them for it.

E-Mail providers can implement WebFinger by creating a special URL (specifically at /.well-known/host-meta) that is an XRD XML document telling the requester a URL at which they can find out more about e-mail addresses on their domain. Google’s, for example, is http://www.google.com/s2/webfinger/?q={uri}. When the WebFinger endpoint is requested with an e-mail address in place of {uri}, Google looks up information about that e-mail’s public profile and provides it in a standardized XRD XML format.

So why WebFinger when OpenID already exists? Users are used to associating their e-mail address with their identity. It’s natural since an e-mail address is (usually) for a specific person. By putting a protocol in place to find out more about an e-mail address without requiring additional input from the user, a host of options become available.

For instance, if I’m an application looking to authenticate using OpenID, I can ask a user for their e-mail address instead of their OpenID URL (something that will confuse mainstream users to no end). Or, if I want to automatcially fill in basic profile information, I can check to see if a parseable profile page is available in a format such as hCard.

Enter Redfinger

Redfinger is a library built to easily consume the WebFinger protocol. Installing it is simple:

gem install redfinger

Using it is just as simple:

require 'rubygems'
require 'redfinger'

finger = Redfinger.finger('youraccount@gmail.com')
finger.open_id.first.to_s # => "http://www.google.com/profiles/youraccount"

Redfinger will query the host of the e-mail domain specified, and, if the Webfinger protocol is supported, retrieve information about that e-mail address including such links as OpenID Provider, hCard URL, and more.

How can you use this today? Well, if you’re an OpenID consumer you can use the above code to try to “intelligently find” an OpenID endpoint from an e-mail address. Of course, it will just about only work with Google at the moment (this is an alpha protocol, after all). Or, you could install the mofo gem (a gem for parsing microformats for web pages) and do some neat things with microformats:

require 'rubygems'
require 'mofo'
require 'redfinger'

finger = Redfinger.finger('account@gmai.com')
card = hCard.find(finger.hcard.first.to_s)
card.fn # => "That GMail user's full name"
card.title # => "The title he/she entered on Google Profile"

Here Redfinger determines a URL that will have hCard information about the e-mail address specified, and the Mofo gem goes out and fetches that address, parsing out the information.

WebFinger is still brand new (Google calls it “alpha”) but it shows some promise for being a great way to make the open web more seamless for users. As always, the Redfinger source code is available on GitHub and RDoc Documentation is available. Check it out!

Comment | 

Simple Mustache JSON Serialization

Mini

by Michael Bleigh

If you’ve taken a look at Mustache, the “stupid in a good way” templating engine, you might know that there are also Javascript Mustache renderers such as Mustache.js. Today we’ve released a small library called mustache_json that allows you to compile your Mustache view objects into JSON, allowing them to be interpreted by Javascript Mustache rendering engines.

What this means for your project is that you will finally have a identical client-side and server-side rendering interface, opening wide the opportunities for pushing more of the rendering work onto the client-side, a boon for many real-time and heavy-interaction applications.

To install mustache_json, just get the gem from Gemcutter:

gem install mustache_json

To use it, simply require 'mustache_json' and all of your Mustache objects will automatically be given a #to_json method. For instance:

require 'mustache_json'

class Person < Mustache
  def initialize(first_name, last_name)
    context[:first_name], context[:last_name] = first_name, last_name
  end
  
  def initials
    "#{context[:first_name][0..0]}.#{context[:last_name][0..0]}."
  end
  
  def listing
    "#{context[:last_name]}, #{context[:first_name]}"
  end
end

bob = Person.new('Bob', 'Bobson')
bob.to_json

This will render into a JSON object that looks like this:

{"last_name":"Bobson","initials":"B.B.","listing":"Bobson, Bob","first_name":"Bob"}

Mustache JSON gives you access to all of the public instance methods you declare in your Mustache as well as any context you have set. It is essentially a fully compiled version of the Mustache view, providing everything another renderer needs to create the actual markup. The JSON back-end for this library is swappable, meaning you can use the JSON gem, JSON pure, ActiveSupport, or Yajl by default (and any other class with an encode method if you’ve got a different library).

Documentation is available on RDoc.info and the source is available on GitHub. Stay tuned for posts in the future about utilizing this library to actually perform identical rendering in Ruby and Javascript.

Comment | 

Quick Tip: Readable Conditional Validations in Rails

Mini

by Michael Bleigh

This is something that many may already use as a best practice, but if not it’s something simple and convenient to add to your repertoire. Sometimes you may have a model that requires additional information if a certain condition is met. For example, I may require a user to add more information about themselves if they wish to be listed publicly, whereas I would not if they do not wish to be listed. By combining ActiveSupport’s Object#with_options and ActiveRecord’s conditional validations, we can implement this behavior in a straightforward and readable manner (assuming here that there is a boolean field called “listed” in the database that is exposed as a checkbox or similar to the user):

class User < ActiveRecord::Base
  # Our standard validations
  validates_presence_of :login
  validates_uniqueness_of :login

  # Validations for listed users
  with_options :if => :listed? do |l|
    l.validates_presence_of :email
    l.validates_length_of :description, :minimum => 100
  end
end

It’s a simple technique that piggybacks off of Rails’s automatic construction of existence query methods (in this case, listed?) for fields in the database combined with the mapping power of with_options and standard conditional validations.

Comment | 

CouchDB-Lucene, CouchDBX, and CouchRest

Mini

by Michael Bleigh

I’ve been playing a lot with CouchDB lately and if you’re on OS X there’s really no easier way to do so than by using CouchDBX, a self-contained application that includes CouchDB, Erlang, and all of the dependencies you need to run Couch.

However, recently I wanted to try the power and functionality of couchdb-lucene for full-text indexing of a CouchDB application on which I was working. It wasn’t immediately obvious to me how to make that happen, so I thought I’d share how I got it working for those who might want to do the same. For the record, I am using the following versions of things:

Unpacking CouchDB Lucene

You will need to place CouchDB Lucene in a convenient location, but first you’ll need to unpack the gZip file. Note that, at least for me, the default Mac unarchiver did not provide a suitable .jar file. Instead, follow the README instructions and extract it using the following command:

unpack200 couchdb-lucene-0.4-jar-with-dependencies.jar.gz couchdb-lucene-0.4-jar-with-dependencies.jar

It doesn’t particularly matter where you put it (I put mine in /usr/local/etc) so long as you remember the location.

Editing the CouchDBX .ini File

Next you will need to edit the CouchDBX local.ini file to add the external for full-text indexing. To access the file, right-click CouchDBX and select “Show Package Contents” then navigate to Contents/Resources/couchdbx-core/couchdb/etc/couchdb/local.ini and open it up in your favorite text editor. You will need to add the following lines to this file, taking note to change the directory to match where you stored your Lucene .jar file.

[couchdb]
os_process_timeout=60000 ; increase the timeout from 5 seconds.

[external]
fti=/usr/bin/java -server -Xmx1g -jar /path/to/couchdb-lucene-0.4-jar-with-dependencies.jar -search

[update_notification]
indexer=/usr/bin/java -server -Xmx1g -jar  /path/to/couchdb-lucene-0.4-jar-with-dependencies.jar -index

[httpd_db_handlers]
_fti = {couch_httpd_external, handle_external_req, <<"fti">>}

All right, that’s all the setup you need to be running CouchDB Lucene! Now you can start up CouchDBX and set up your first search indexes.

Creating a Full-Text Index View

To create a full-text index view, you simply need to add a “fulltext” field to one of your design documents. The URL structure for accessing CouchDB Lucene searches is as follows:

http://localhost:5984/database_name/_fti/design_doc_name/index_name?q=your+query+here

Where database_name is any database you have on your system, design_doc_name is any design document in your database, and index_name is a fulltext index you defined. For instance, if I had a CouchRest generated design doc for a bunch of music, I might have a design document that looks something like this:

{
  "_id":"_design/Song",
  "_rev":"af12a4b12af1b24afbf244f1",
  "fulltext":{
    "my_search":{
      "index":"function(doc) { if (!doc['couchrest-type'] == 'Song') return null; var ret = new Document(); ret.add(doc.title); ret.add(doc.artist); return ret; }"
    }
  }
}

I would then be able to access the search results with this URL:

http://localhost:5984/myapp/_fti/Song/my_search?q=Ben+Folds

Awesome! We now have full-text indexing up and running on CouchDBX!

Bonus: CouchRest Lucene

I use CouchRest extensively in my Ruby CouchDB projects, and I wanted to be able to integrate the new Lucene searches easily. I found this post that added a bit of functionality, but I wanted to be able to integrate with ExtendedDocument (and the snippet was also slightly outdated), so I’ve updated it. Just add this sometime after you include CouchRest:

class CouchRest::Database
  def search(design, index, query, options={})
    CouchRest.get CouchRest.paramify_url("#{@root}/_fti/#{design}/#{index}", options.merge(:q => query))
  end
end

class CouchRest::ExtendedDocument
  def self.search(index, query, options={})
    options[:include_docs] = true
    ret = self.database.search(self.to_s, index, query, options)
    ret['rows'].collect!{|r| self.new(r['doc'])}
    ret
  end
end

What this snippet does is allows you to perform searches on a database directly or by calling a search method on an extended document. Let’s look at a couple examples to see how it would work:

@db = CouchRest.database!("http://localhost:5984/myapp")

@db.search('Song','my_search', 'Ben Folds', :include_docs => true)

# The following is equivalent to the above, but will automatically
# include the docs and cast the result rows into ExtendedDocuments
Song.search('my_search', 'Ben Folds')

Now that we have this set up, we’re ready to go forth and build full-text search into our CouchDB apps. I hope this is helpful to some who have become somewhat familiar with CouchDB but are looking to push it a little further and try out some of the more advanced usages of CouchDB in their applications.

Comment | 

LA Ruby Conference 2009 Recap

Mini

by Brendan Lim

Pradeep Elankumaran and I just came back from the very first LA Ruby Conference (Twitter), which was held in Tustin, CA. We didn’t know what Tustin had to offer or what to expect, since it was the first time either of us has visited Tustin. When we arrived at the venue, we were in awe of the few million dollars worth of automobiles surrounding the stage. The conference was held in the Marconi Automotive Museum, which is filled with Ferrari’s, Lamborghini’s, F1 cars — you name it. The event ended up being a huge success due to the great venue and the amazing set of talks, with a final count of 115 attendees.



There were many great talks that ended up covering a wide variety of topics. You can view the whole schedule here. One very unique talk was by Ron & Damen Evans with their unveiling of Flying Robot, a platform for Ruby Arduino Development. The Ruby powered blimp, flew around the museum, while being controlled by a Wii-mote.



Pradeep gave his talk on Fast and Scalable Front/Back-end Services using Ruby, Rails and XMPP and I gave my talk on Mobilizing Your Rails Application. The kind fellas from Confreaks were there recording each talk as well, so be sure to look out for those when they become available.

From flying robots to creating cross-platform native mobile applications, it’s quite clear that there are some very exciting things going on in the world of Ruby development. Our thanks and congratulations goes out to Coby Renquist, JR Fent, all of the great speakers and everybody else who helped to put on such a great conference. We are both looking forward to going back to Tustin in 2010.

Comment | 

Present.ly and XMPP

Mini

by Pradeep Elankumaran

Along with the launch of Presently.com, we quietly revamped the backend architecture of Present.ly to better use the eXtensible Messaging and Presence Protocol (XMPP) as the standard message delivery system. You may have noticed near-instant updates on the new web interface — this is primarily due to the super-fast messaging features of eJabberd, the XMPP server that Present.ly runs on.


We believe that XMPP will play a bigger role powering dynamic, real-time web applications in the coming years and have previously blogged as such. While most people in the industry know of XMPP only in its instant messaging role, the fact that there are fully fleshed out specifications for most common enterprise messaging problems as subsets of the XMPP specification is often sadly overlooked.

So what does this mean for Present.ly? In the short term, as you may have already noticed, you will see a major speed improvement posting and receiving updates. In the long term, we are planning on making our user interface a lot more dynamic — details are top-secret at the moment. We are also working on moving over our notification systems completely to XMPP, which will result in you receiving update notifications more rapidly over all your devices. As we grow, we’ll be leveraging eJabberd’s high scalability (due to it being written in Erlang) to provide a seamless, quick user experience.

We are also actively contributing back to the open-source XMPP community. Read about ruby_bosh, the first Ruby library to handle BOSH sessioning in your Ruby applications. We have also made various stability and speed fixes to the stropheruby library, which is based on the libstrophe C library (announcement soon). Both are available on Github for general use. Intridea’s proud to be a part of the XMPP community, and will be heavily using and promoting the technology with both our products and services.

Comment | 

March 16, 2009

ruby rails documentation

Document Your Models the Easy Way

Mini

by Joe Grossberg

At a recent DCRUG meeting, I was surprised by how many Rubyists, novice and experienced, were unfamiliar with two great documentation tools: annotate_models and RailRoad.

I suspect this is because they relate to the dreaded “d” word: documentation. This is a shame, because these two tools make basic documentation a cinch.

annotate_models

One of the best things about the popular Ruby ORM libraries like ActiveRecord and DataMapper is that you don’t need to spell out the attributes of your models; they are inferred from the database.

Sometimes, though, it is useful to have this information at hand, instead of firing up script/console or your database to answer a simple question like: “Did he call it User.first, User.firstname or User.first_name?”

The annotate_models gem, originally written by Dave Thomas creates a nice comment block at the top of each model, displaying information about the underlying columns/attributes:

# == Schema Information                                                         
# Schema version: 20090311145521                                                
#                                                                               
# Table name: groups                                                            
#                                                                               
#  id                     :integer(4)      not null, primary key                
#  name                   :string(255)                                          
#  description            :text                                                 
#  created_at             :datetime                                             
#  updated_at             :datetime                                             
#  status                 :integer(4)      default(1)  
#                                                                               

Producing this documentation is as simple as running annotate in your Rails application’s root directory.

Another nice aspect of annotate_models: it will only modify the headers of models that have changed since the last time it was run.

RailRoad

Another useful view of a Rails application, especially a legacy one, is the big picture: i.e., how do all the models (and controllers) fit together? This can be especially daunting when you are following the trail of :belongs_to and :has_and_belongs_to from one file to another.

A free tool, Javier Smaldone’s RailRoad, can tell you all that information at once, by generating a diagram of the models and key information about them, like names, attributes, associations and inheritance relationships.

model diagram for depot application

A minor inconvenience is that the project’s models are outputted in .dot format. This is easily converted into .svg and .png if, like me, you prefer those formats.

Because I do this often, I have added the following alias to my ~/.bashrc and just run rr as needed.

alias rr='railroad -M | dot -Tsvg > doc/models.svg; railroad -M | neato -Tpng > doc/models.png'

If you are happy with .dot files (e.g. you are a GraphViz user), it’s as simple as running railroad -M.

Another cool feature: you can use RailRoad to document your controllers too; just pass it the -C flag instead of -M.

Conclusion

Now, I know this hardly suffices as thorough documentation. However, I also know that I’ve been in web development for a decade and most projects I’ve seen have no documentation at all.

Complete documentation would be great, but it is time-consuming and requires good written communication skills — a tall order for your typical software engineer. Keeping that documentation up-to-date with rapidly-evolving software is even more challenging.

These two tools provide great “bang for the buck”. Check out the repository and run these two commands, and suddenly a legacy Rails application is far less opaque.

I run the commands manually, but you may also consider automating it as part of your build process, or even as a post-hook for rake db:migrate.

Either way, you can trust me on this: if you spend fifteen minutes installing these gems, a few seconds running annotate and rr, you will save hours over the course of your projects.

Comment | 

Easily Search on ActiveRecord Attributes

Mini

by Raymond Law

Rails’s named_scopes are great, and the ability to chain named_scopes together are even better. I am sure many of us have done something like this before:

  User.active.live_in('Virginia')

That would give you the active users who live in the state of Virginia. You would define something like these in your User model:

  named_scope :active, lambda { |status| { :conditions => { :status => status } } }
  named_scope :live_in lambda { |state| { :conditions => { :state => state } } }

One recent client project has a model where the database table has 30-something columns. Doing these named_scopes became tedious and repetitive. That makes it not fun anymore.

So Dave Pranata and I wrote the searchable_attributes Rails plugin so we could stop worrying about explicitly defining these named_scopes once and for all.

To use it, you just install it like any other Rails plugin:

script/plugin install git://github.com/rayvinly/searchable_attributes.git

The plugin will automatically define a bunch of named_scopes for you if you include this in your model:

class User < ActiveRecord::Base
  searchable_attributes
end

You can then search on your models with something like this:

  def index
    @users = User.with_first_name_equal('Gilbert').with_last_name_equal_if_not_null('Arenas').with_address_like('Main Street').with_age_greater_than(25).with_state_equal(['VA', 'MD', 'DC']).with_position_end_with('Guard').with_salary_within_inclusive((100..10000)).with_injured_equal(true).with_join_date_greater_than_or_equal_to(5.years.ago)
  end

Take a look in the plugin’s lib/searchable_attributes.rb for a list of automatically defined named_scopes.

Comment | 

ruby_bosh - an XMPP BOSH session initializer

Mini

by Pradeep Elankumaran

Hot on the heels of my post on why XMPP will be huge, here’s a ruby library to pre-initialize BOSH sessions in your Ruby web applications. This feature allows you to by-pass exposing your user’s XMPP credentials in your HTML views.



The process follows as such:


  1. Start your XMPP server and create an account for your web application user.

  2. In your Ruby application, use ruby_bosh to initialize a new BOSH session using the user’s xmpp username and password.

  3. Pass the identifiers returned from ruby_bosh to your template engine as variables.

  4. Bind the template variables to Javascript variables.

  5. Use a Javascript-based BOSH connector (like Strophe) to attach to the pre-existing session using the identifiers.

There are many XMPP servers and BOSH connection managers out there, but as of now this library has only been tested with eJabberd 1.2+. Please feel free to fork and submit a pull request if you’d like to contribute.



The plugins and documentation can be found at: http://www.github.com/skyfallsin/ruby_bosh



Jack Moffit’s written a Django/Python example here.

Comment | 

PayPal Recurring Billing with ActiveMerchant in Ruby on Rails

Mini

by Raymond Law

PayPal is an easy-to-use tool for making payments and ActiveMerchant is a great Ruby library for payment processing. A lot of us already have PayPal accounts for eBay and it works great in auctions, where you pay just once. However, ActiveMerchant currently does not support recurring billing through PayPal.

One requirement of a recent project was to charge for a monthly or yearly subscription plan, via PayPal. Therefore, I did some Googling and found that Jon Baker has already extended ActiveMerchant to add this functionality using PayPal’s Name-Value Pair (NVP) API. However, as Cody Fauser pointed out, the NVP API was taken out from ActiveMerchant, so I had to implement that with PayPal’s SOAP API.

First, download this file and put it in vendor/plugins/active_merchant/lib/active_merchant/billing/gateways/. Use the GitHub from now because maintaining a separate file download is too troublesome. Alternatively, there’s a fork on GitHub at http://github.com/rayvinly/active_merchant/.

In your controller, after a user selects one of your subscription plan, the form goes to the checkout action:

  def checkout
    response = gateway.setup_agreement(:description => description, :return_url => return_url, :cancel_return_url => cancel_return_url)
    redirect_to gateway.redirect_url_for(response.token)
  end

This redirects the user to PayPal so he can login and read the description you provided. After he confirms, he is redirected back to your application’s return_url, which I set it to be the complete action below. If he cancels, he is redirected back to the cancel_return_url. You can set cancel_return_url to be the plan selection page where he can choose a different plan.

If he confirms, here’s the complete action:

  def complete
    token = params[:token]
    response = gateway.create_profile(token, :description => description, :start_date => start_date, :frequency => frequency_in_months, :amount => amount_in_dollars, :auto_bill_outstanding => true)
  end

    # Save this profile_id in your transactions table.  This is used to cancel/modify the plan in the future.
    profile_id = response.params["profile_id"]

    if response.success?
      flash[:notice] = "Your PayPal account was successfully set up for the <strong>#{description}</strong> payment plan."
      redirect_to login_path
    else
      flash.now[:notice] = "There was a problem setting up your PayPal account for the <strong>#{description}</strong> payment plan"
      render cancel_url
    end
  end

I default the frequency to be in months and turn on auto_bill_outstanding because that is what I need, but you can look at the file you downloaded and the PayPal documentation to see what other options are available. In particular, read these two PDFs:

If the user wants to cancel the payment plan, a cancel action would look like:

  def cancel
    response = gateway.cancel_profile(paypal_profile_id, :note => 'Payment plan was canceled by user')
    flash[:notice] = 'You have successfully canceled your membership'
  end

paypal_profile_id is the profile_id you saved in the complete action from above. Keeping this profile_id is very handy.

That’s it. Enjoy making money!

Comment | 

February 4, 2009

ruby rails university training

Rails Training with Intridea University

Mini

by Adam Bair

I’m pleased to introduce a new service called Intridea University. It’s been in the works for a long time and we’re happy to be able to announce it’s arrival.

Registration is now open for “Introduction to Ruby on Rails” instructed by Joe Grossberg and myself. This course has been designed to introduce anyone familiar with programming to the popular Ruby on Rails framework.

This extended 3-day course will held at The Hotel George in Washington, D.C. starting on Friday, February 27th and ending in the afternoon on Sunday, March 1st. Breakfast, lunch, refreshments, and wireless internet will be provided throughout the weekend.

The Hotel George is a boutique hotel located in the Capital Hill district right down the street from Washington’s Union Station which has metro access to the entire area including Reagan National Airport and Baltimore International (via Amtrak).

We’ve scheduled 3 full days of training to make sure that we can go in-depth on important topics and have plenty of time to work directly with our students. Intridea University courses are hand-crafted and instructed by Intridea developers with knowledge cultivated though years of experience developing quality applications.

You’ll leave with enough knowledge to start building your own Rails applications and with the skills required to continue learning more advanced techniques.

There are 20 spaces available each costing $1250. If you register by February 19th, you can get the Early Bird rate of $995. Register now! Please visit Intridea University to learn more.

Come and join us for a weekend!

Comment | 

January 28, 2009

ruby rails dry paperclip avatar

HasAvatar: Defining an Application Vocabulary

Mini

by Michael Bleigh

One of my favorite techniques to DRY up a Rails application is to pull out common functionality into a simple “vocabularized method,” by which I mean a simple descriptive method call that can be made from within your model or controller definition. For instance, in some applications I might have multiple models that have an “avatar.”

These avatars all behave the same and should do the same things so I don’t want to just repeat myself in the code. Instead I set up a file called has_avatar.rb inside my config/initializers folder. We use Paperclip for attachment handling at the moment, so I am going to create a wrapper for the specific Paperclip functionality I need for the avatars. Here’s the code:

module HasAvatar
  STYLES = { :large  => ["200x200#", :png],
             :medium => ["100x100#", :png], 
             :small  => ["70x70#", :png],
             :little => ["50x50#", :png],
             :tiny   => ["24x24#", :png] }
             
  def self.included(base)
    base.extend ClassMethods
  end
  
  module ClassMethods
    def has_avatar
      has_attached_file :avatar,
                        PAPERCLIP_DEFAULTS.merge(
                          :styles => HasAvatar::STYLES,
                          :default_style => :medium,
                          :default_url => "https://assets.presentlyapp.com/images/avatars/missing_:style.png",
                          :path => ":account/avatars/:class/:login/:style.:extension"
                        )
    end
  end
end

ActiveRecord::Base.send :include, HasAvatar

We define a module, HasAvatar that will add a new class method called has_avatar into whatever class it is included. I defined a constant STYLES that lets me access the style hash outside of the attachment definition. A final piece of DRYness in the code is the PAPERCLIP_DEFAULTS constant which is just the default setup for all attachments (S3 Bucket, etc.) and I override the options I need for the avatars by merge-ing them in.

class User < ActiveRecord::Base
  has_avatar
end

class Group < ActiveRecord::Base
  has_avatar
end

Now both users and groups will have all of the expected Paperclip functionality without having to repeat ourselves. This is a simple example but it shows the general practices behind building your application vocabulary, which is just my made-up term for the abstract reusable components that are specific only to this application. Of course, if it’s useful outside of the application, you might want to just go ahead and pluginize it!

The usefulness of these abstracted methods also comes in through the inherently polymorphic nature of Ruby. Throughout my code I can write helpers, views and more to support avatars without caring whether the object in question is a User or a Group. Basically, the DRYer you start the DRYer you stay.

Comment | 

Announcing the Badger Rails Plugin

Mini

by Raymond Law

Badger is a simple Rails plugin that creates photo badges. A site often allows its
users to upload a profile image. A profile image is just that, an image
resized to fit in a predefined space to show up in the user’s profile.

With Badger, you can have something prettier – a badge that shows the user-
uploaded image on top of another image that identifies the user as a part of
the community. We have company badges, security badges, so why not web
badges to have your users show off his/her affection for your site?

Badger works by accepting cropping parameters of the overlay image in a hash
(x1, y1, width, height), which is used to crop the overlay image. It then
resizes the cropped image to the size specified by composite_width and
composite_height in badger.yml. Finally, it places the resized image on top
of the background image at location specified by composite_x and composite_y
in badger.yml. The resulting image is saved back to either the filesystem or
Amazon S3, using attachment_fu.

Badger requires the attachment_fu plugin, ImageMagick, and MiniMagick. Also,
the JavaScript Image Cropper UI can be used to obtain the cropping parameters
from the users.

Configuration

When this plugin is installed , the badger.yml will be copied to the config
directory. You need to specify the following:

  1. background : filename of the background image, searching from public/images
  2. composite_x : top left corner of the overlay image location in x
  3. composite_y : top left corner of the overlay image location in y
  4. composite_width : width of the overlay image in pixels
  5. composite_height : height of the overlay image in pixels



For example, I want to overlay an image on top of a background image
(badge.jpg). The box for the overlay image should be 30 pixels in width and
20 pixels in height, and it should appear at (x, y) = (60, 80) of the
background image. My badger.yml then looks like:

  development:
    background: badge.jpg
    composite_x: 60
    composite_y: 80
    composite_width: 30
    composite_height: 20

Example

In the model that you use to store attachments:

  class Photo < ActiveRecord::Base
    has_attachment :content_type => :image,
                   :storage => :s3,
                   :max_size => 1.megabytes,
                   :resize_to => '320x200>',
                   :thumbnails => { :thumb => '100x100>' },
                   :processor => :MiniMagick
    validates_as_attachment
    has_badge :storage => :s3
  end

In the controller:

  def create_my_awesome_badge
    @photo = Photo.find(params[:id])
    # params[:crop_coord] is a hash with indexes x1, y1, width, height
    @photo.create_badge(params[:crop_coord])
  end

Improvements Needed

Please feel free to submit patches for bug fixes and improvements.
Specifically, I would like to:

1. Use something nicer than system(“convert blah…”), but couldn’t get it
to work. I don’t think Minimagick supports compositing images, so
RMagick may have to be used, but is it worth the heavy memory
consumption?

2. Make it more flexible (i.e. accept background image and composite
params dynamically instead of in badger.yml). Maybe pass them in the
call to create_badge?

Comment | 

Deploying your Rails applications with Phusion Passenger

Mini

by Raymond Law

There have been several methods to deploy an Ruby on Rails application. Until recently, the most popular is to run Apache and proxy balance to multiple Mongrel instances that are running simultaneously.

Passenger, developed by Phusion, is the new kid entering the Rails deployment market. Everyone has been using the Apache PHP module for years and deploying a PHP applications is a snap. This has not been possible with Rails until Passenger. It is extremely easy, and you can still use Capistrano to automate deployment. I will show you how I get it to work on Ubuntu.

sudo gem install passenger
passenger-install-apache2-module

Update: Phusion just released Passenger 2.0 RC 1. You can download this version and do gem install passenger-1.9.0.gem instead. But I had an error compiling it on Mac OS X Leopard. hongli pointed me to use the version from GitHub that has the fix and it works like a charm. Thanks Phusion guys.

To get it from GitHub:

git clone git://github.com/FooBarWidget/passenger.git

I created a separate /etc/apache2/mods-available/passenger.load and it contains the following:

For 1.0.5:

LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/ext/apache2/mod_passenger.so
RailsSpawnServer /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/bin/passenger-spawn-server
RailsRuby /usr/local/bin/ruby

For the GitHub version (Of course the path will look different depending on where your git clone is):

LoadModule passenger_module /home/rlaw/downloads/passenger/ext/apache2/mod_passenger.so
PassengerRoot /home/rlaw/downloads/passenger
PassengerRuby /usr/local/bin/ruby

I then tell Apache to load the Passenger module:

a2enmod passenger

Now, I create a virtual host configuration for one of my Rails app in /etc/apache2/sites-available/myapp:

<VirtualHost *:80>
  ServerAdmin webmaster@myapp.com
  ServerName myapp.com

  DocumentRoot /home/deploy/apps/myapp/current/public

  <Directory /home/deploy/apps/myapp/current/public>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>

  LogLevel warn
  ErrorLog /var/log/apache2/myapp/error.log
  CustomLog /var/log/apache2/myapp/access.log combined
</VirtualHost>

I then restart Apache:

sudo /etc/init.d/apache2 reload

When you need to restart your application because you have changed some code that Rails does not reload in production, just do:

touch /home/deploy/apps/myapp/current/tmp/restart.txt

I have not tried their Ruby Enterprise Edition yet. They claim substantial memory and speed improvement at RailsConf 2008, so it will be interesting to see how that develops.

Comment | 

Announcing Fu-fu: The Profanity Filter for Rails

Mini

by Adam Bair

That’s the most foul, cruel, and bad-tempered word you ever set eyes on!

Look, that word’s got a vicious streak a mile wide! It’s a killer!

There will be no killer words in this application: Behold the mighty Fu-fu! And there was much rejoicing… But first, a little history on Fu-fu: The Profanity Filter for Rails.

A Little History

Recently, I needed a simple (profanity/cuss/swear/bad word) filter for a Rails app, so I hit up Google for the answer as this seemed like a problem that should have been solved by an expert. Sadly, this was not the case.

Over the next day or so I was able to get a simple prototype up and running in our application and that’s the way it stayed for the next couple weeks. Then I realized that this was reason I wasn’t able to find a profanity filter plugin on Google.

Upon closer inspection it seems that people are building their own filters and leaving it at that. Almost being guilty of this, I decided that it was time to give back to the community and get a profanity filter plugin out in the wild.

I was able to publish the first version of the Profanity Filter during the Community Code Drive at RailsConf 2008. Hacking in the same room as DHH, David Chelimsky, Chad Fowler, Rich Kilmer, Marcel Molina Jr., and the entire Intridea team is a great motivator.

During RailsConf we decided that the plugin needed a real name; “Profanity Filter” wasn’t cutting it. Someone suggested fu-fu pronounced ‘eff-you-foo’. That was promptly shortened to ‘foo-foo’. How can you not love something named Fu-fu that deals with profanity and abuses plugin idioms at the same time?

Continue Rejoicing (Examples!)

The interface for Fu-fu is clean and straight forward. For example. lets say that ‘frak’ is a common curse word.

class Post < ActiveRecord::Base
  profanity_filter :title, :body
end

post = Post.create(:title => 'Fraking title', :body => 'What a bunch of frak')

post.title          #=> '@#$% title'
post.title_original #=> 'Fraking title'

post.body           #=> 'What a bunch of @#$%'
post.body_original  #=> 'What a bunch of frak'

By default the filter will replace common curses with the standard curse notation of ‘@#$%’. Fu-fu is also has the ability to do dictionary replacements:

class Post < ActiveRecord::Base
  profanity_filter :title, :body, :method => 'dictionary'
end

post = Post.create(:title => 'Fraking title', :body => 'What a bunch of frak')

post.title          #=> 'fr*k*ng title'
post.body           #=> 'What a bunch of fr*k'

Fu-fu comes with a default dictionary file that replaces all vowels with asterisks (*).

You can also add an exclamation point to the end of the filter call (profanity_filter!) and have the method save the filtered text to the database (although this is not recommended for most applications).

You can also call Fu-fu directly:

ProfanityFilter::Base.clean('frak')               #=> '@#$%'
ProfanityFilter::Base.clean('frak', 'dictionary') #=> 'fr*k

Todos and Fixes

But alas, there is still danger in Caerbannog. As with all things, there is room for improvement.

* better filter regex, doesn't currently catch things like 'f-r-a-k'
* needs support for multiple dictionaries and configuration
* needs support for different levels of filtering (prude, normal, weak, etc)

Installation

To install the Fu-fu: The Profanity Filter on Edge Rails or Rails 2.1 and greater:

script/plugin install git://github.com/adambair/fu-fu.git

On earlier versions of Rails:

git clone git://github.com/adambair/fu-fu.git vendor/plugins/fu-fu

Resources

Bug tracking is available through the Fu-fu Lighthouse project. Also, feel free to contribute. I’ll be happy to accept patches and push requests for reasonable fixes and additions as long as they come with test coverage.

The source code is available on GitHub.

For general discussion about the plugin, please use the forums and wall of Fu-Fu’s Acts As Community Profile

Thanks to the Intridea team for their time, contributions, and suggestions. I’ve had a great time building Fu-fu and I hope someone may find it useful.

Comment | 

Mash - Mocking Hash for total poser objects

Mini

by Michael Bleigh

Note: Development of Mash has now moved to Hashie, a generic Hash toolkit.

There are a number of times when I need something like an OpenStruct with a little more power. Often times this is for API-esque calls that don’t merit a full on ActiveResource. I wrote a small class for use with my ruby-github library and wanted to make it a separate gem because I think it’s pretty useful to have around.

Usage

Basically a Mash is a Hash that acts a little more like a full-fledged object when it comes to the keyed values. Using Ruby’s method punctuation idioms, you can easily create pseudo-objects that store information in a clean, easy way. At a basic level this just means writing and reading arbitrary attributes, like so:

author = Mash.new
author.name # => nil
author.name = "Michael Bleigh"
author.name # => "Michael Bleigh"
author.email = "michael@intridea.com"
author.inspect # => <Mock name="Michael Bleigh" email="michael@intridea.com">

So far that’s pretty much how an OpenStruct behaves. And, like an OpenStruct, you can pass in a hash and it will convert it. Unlike an OpenStruct, however, Mash will recursively descend, converting Hashes into Mashes so you can assign multiple levels from a single source hash. Take this as an example:

hash = { :author => {:name => "Michael Bleigh", :email => "michael@intridea.com"},
       :gems => [{:name => "ruby-github", :id => 1}, {:name => "mash", :id => 2}]}

mash = Mash.new(hash)
mash.author.name # => "Michael Bleigh"
mash.gems.first.name # => "ruby-github"

This can be really useful if you have just parsed out XML or JSON into a hash and just want to dump it into a richer format. It’s just that easy! You can use the ? operator at the end to check for whether or not an attribute has already been assigned:

mash = Mash.new
mash.name? # => false
mash.name = "Michael Bleigh"
mash.name? # => true

A final, and a little more difficult to understand, method modifier is a bang (!) at the end of the method. This essentially forces the Mash to initialize that value as a Mash if it isn’t already initialized (it will return the existing value if one does exist). Using this method, you can set ‘deep’ values without the hassle of going through many lines of code. Example:

mash = Mash.new
mash.author!.name = "Michael Bleigh"
mash.author.info!.url = "http://www.mbleigh.com/"
mash.inspect # => <Mash author=<Mash name="Michael Bleigh" info=<Mash url="http://www.mbleigh.com/">>>
mash.author.info.url # => "http://www.mbleigh.com/"

One final useful way to use the Mash library is by extending it! Subclassing Mash can give you some nice easy ways to create simple record-like objects:

class Person < Mash
  def full_name
    "#{first_name}#{" " if first_name? && last_name?}#{last_name}"
  end
end

bob = Person.new(:first_name => "Bob", :last_name => "Bobson")
bob.full_name # => "Michael Bleigh"

For advanced usage that I’m not quite ready to tackle in a blog post, you can override assignment methods (such as name= and this behavior will be picked up even when the Mash is being initialized by cloning a Hash.

Installation

It’s available as a gem on Rubyforge, so your easiest method will be:

sudo gem install mash

If you prefer to clone the GitHub source directly:

git clone git://github.com/mbleigh/mash.git

This is all very simple but also very powerful. I have a number of projects that will be getting some Mashes now that I’ve written the library, and maybe you’ll find a use for it as well.

Comment | 

Beboist -- Updates and Attention

Mini

by Pradeep Elankumaran

Our friends at Bebo have selected our Beboist plugin to be one of their featured Bebo Social API libraries.

This joyous occasion can only be properly acknowledged by the announcement that Beboist has now been moved to Github, a Git repository host where the cool kids play nowadays. We feel that Github’s convenient fork-edit-push code publishing mechanism will only help Beboist grow even quicker to become a prominent solution for working with the Bebo API.

The old SVN repository will still remain up, but all future development will take place on Github.

So, without further ado — here’s the Beboist Github repository:

http://github.com/skyfallsin/beboist/tree/master

You will install this plugin from your RAILS_ROOT directory as such:

git clone git://github.com/skyfallsin/beboist.git vendor/plugins/beboist

Git has a slight learning curve — here are a few resources to help you get started if you have never used it before: SVN to Git Crash Course, Git Tutorial

Intridea’s Public Trac is still up for bug reports.

Comment | 

acts_as_community private beta

Mini

by Dave Naffis

Today Intridea launched the private beta of acts_as_community, a community site for Ruby and Rails developers.

acts_as_community is a place for Rubyists and Rails developers to gather and interact. Our hope is to bring the community closer together in collaboration and communication so that everyone can benefit from others' experiences.

If you would like to join email us at aac@intridea.com for the beta key.

Comment | 

Beboist - A Rails Plugin for the Bebo Social API

Mini

by Pradeep Elankumaran

UPDATE

Click here for the latest on Beboist


The Beboist plugin provides a Rails interface to the Bebo Social Networking API.

The plugin was designed from the ground-up to be flexible enough to accommodate
any changes to the API, while at the same time providing a clean interface
that will be familiar to most Rails developers.

Setup

Ensure that the json gem is installed on your system and the Beboist plugin is installed in your vendor/plugins folder:

gem install json
script/plugin install http://svn.intridea.com/svn/public/beboist</pre>

Generate your config/bebo.yml file using

script/generate beboist_settings</pre>

Fill in your appropriate app settings in config/bebo.yml. Ensure that your app name is right.

Generate the first migration for your users table using:

script/generate beboist_user_migration</pre>

Migrate your database using

rake db:migrate</pre>

In your application.rb, insert the following filters:

before_filter :reject_unadded_users
before_filter :find_bebo_user</pre>

Write your app, and keep an eye on your logs to catch any possible error messages.

API Reference

The methods listed in the Bebo API Documentation are mapped to Ruby classes in the following manner:

users.get_info(uids => "1,2,3", fields => "first_name, last_name")
  # BECOMES
BeboUsers.get_info :uids => [1,2,3], :fields => ["first_name", "last_name"]

Notes

The Beboist plugin uses Bebo’s JSON API, and the ‘json’ gem to directly convert JSON objects to Ruby. It works with Rails 2.0+, but has not been tested on Rails 1.2. Check the README for more details, and file tickets at Intridea’s Public Trac

Comment | 

OpenSocial, Buzz and the Tao of Releasing an API

Mini

by Pradeep Elankumaran

Generate the Right Buzz

OpenSocial was released the 1st of November, and there was much rejoicing. Developers rushed to the official site to see what exactly Google was up to. Facebook developers everywhere crossed their fingers as the page loaded up, hoping to find a means of escape from the FBMLized, constantly-changing hell they were experiencing. Surely, Google will have the answer! This is Google we’re talking about — they wrote Gmail, remember the buzz for that launch? They’ll surely deliver! Right?

Release the right thing at the right time (or ‘First Impressions Matter’)

November 2nd was the first day of RubyConf 2007, and while I saw many a Rubyist’s Macbook Pro loading up the API site during the morning sessions – I would say that it’s within reason to declare that there were no libraries or even hacky interface wrappers written that night. This was partly because Google has YET to release the actual meat of the API — the RESTful interfaces to their data. What the developers got on Thursday was a tiny set of extensions to Google’s pre-existing Google Gadget API, which is primarily written in Javascript. Google, if you’re reading this, know that you would have had a beautiful Rails plugin for OpenSocial a day after launch if you had only came through for the early adopters and opened up the REST interface. Release the whole API (or something respectable and usable) if you want to make a solid first impression.

Don’t frustrate your developers

The developers who actively seek out your API and are excited about it at the beginning are the ones who know a good thing when they see it. Don’t alienate them. The Gadget Javascript extensions are great for tiny widgets, but developing with those brings forth their own set of problems. Orkut has an extremely annoying caching bug that pretty much forces developers to add/test/remove/add their app every time they make a change — not a good start, we are no longer in the dark ages. This brings me to my next point – why just Orkut?! Brazil and India are Orkut’s main consumers, or at the very least, the only people who use it pretty much exclusively (even though I hear rumors of hi5 making major strides in South Asia). The last I heard, Friendster, hi5, LinkedIn and Ning were also launch partners, why are my sandboxed apps not running on their sites as well at this moment? Good developers love an all-encompassing solution rather than a targeted one. If one of these developers writes an app for Orkut now, and finds later when LinkedIn or Friendster finally opens up their sites as containers, that their code does not run as well as promised, Google loses trust, credibility and karma points.

In theory, OpenSocial is fantastic — I will not deny that. In time, I can see that it will be a sweet little platform for writing network-independent social apps. The pressure is on, however. The VCs are probably loving this, considering what Facebook apps are worth now, and Google needs to deliver a flawless platform that is ready to whip out of the gate and crush everything in its path. Intridea will be tracking OpenSocial quite closely, stay tuned for more in-depth posts quite soon.Michael Arrington announced OpenSocial on TechCrunch two days before its official release. Prior to that, there were whispers everywhere about Google’s new social platform, but not many seemed to know what exactly was about to go down. Needless to say, this is good buzz. Two days before ‘launch’ the overwhelming mood among web developers, especially us who dwell in the realms of social networking, was one of intense (even feverish at some points) anticipation. What unfolded over the next few days, combined with what we observed of Facebook’s API venture, provides us a set of best practices that we can apply to an API release.

Comment | 

October 27, 2007

rails ruby tips plugin Rails

Improved BetterNestedSet Plugin

Mini

by Adam Bair

First the database migration used in all examples (using Rails 2.0 sexy migrations):

class CreateClassifications < ActiveRecord::Migration
  def self.up
    create_table :classifications do |t|
      t.integer :parent_id
      t.integer :lft
      t.integer :rgt
      t.string  :name
      t.text    :description
      t.timestamps
    end
  end

  def self.down
    drop_table :classifications
  end
end

Please note that the left and right columns are named in such a way that they will not conflict with database reserved words commonly used in join statements.

Then the code:

class NestedSet < ActiveRecord::Base
  acts_as_nested_set

  def self.all_parents
    self.roots.map do |root| 
      (root.full_set.collect {|child| child if child.children.size > 0}).compact.flatten
    end
  end

  def self.all_leaves
    self.roots.map do |root| 
      (root.full_set.collect {|child| child if child.children.size == 0}).compact.flatten
    end
  end

end

This code works - but works slowly and yields horrific SQL. The reason it's slow and horrific is because you need to hit each node in the tree to test for it's number of children. This is less than ideal especially if you need to do this regularly (or on a tree with hundreds of nodes) - which leads us to the next iteration:

class NestedSet < ActiveRecord::Base
  acts_as_nested_set

  def self.all_parents
    self.find(:all, :conditions => "rgt <> lft + 1")
  end

  def self.all_leaves
    self.find(:all, :conditions => "rgt = lft + 1")
  end

end

This works much better and is far more efficient. Each call to the class method makes a single query to the database. The reason the we can do this is because of the way nested sets work. A good explaination of this can be found in the BetterNestedSet README:

An easy way to visualize how a nested set works is to think of a parent entity surrounding all
of its children, and its parent surrounding it, etc. So this tree:

  root
    |_ Child 1
      |_ Child 1.1
      |_ Child 1.2
    |_ Child 2
      |_ Child 2.1
      |_ Child 2.2

Could be visualized like this:
    ___________________________________________________________________
   |  Root                                                             |
   |    ____________________________    ____________________________   |
   |   |  Child 1                  |   |  Child 2                  |   |
   |   |   __________   _________  |   |   __________   _________  |   |
   |   |  |  C 1.1  |  |  C 1.2 |  |   |  |  C 2.1  |  |  C 2.2 |  |   |
   1   2  3_________4  5________6  7   8  9_________10 11_______12 13  14
   |   |___________________________|   |___________________________|   |
   |___________________________________________________________________| 

The numbers represent the left and right boundaries.  The table then might
look like this:

   id | parent_id | lft  | rgt  | data
    1 |           |    1 |   14 | root
    2 |         1 |    2 |    7 | Child 1
    3 |         2 |    3 |    4 | Child 1.1
    4 |         2 |    5 |    6 | Child 1.2
    5 |         1 |    8 |   13 | Child 2
    6 |         5 |    9 |   10 | Child 2.1
    7 |         5 |   11 |   12 | Child 2.2

You can also check out additional nested set explanation in an article titled "A Nested Set Implementation..." (paying special attention to the illustrations in section #3).

Going back to our example, there's one more thing we can to do make this one step better - move our methods into the plugin implementation. This makes sense as our class methods are not directly related to our application logic and pertain mainly to nested set behavior.

You can add a version of our methods to the nested set plugin by adding to the ClassMethods module in better_nested_set.rb in the lib folder of the BetterNestedSet plugin with the following:

def parents
  acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:right_column]} <> #{acts_as_nested_set_options[:left_column]} + 1)", :order => "#{acts_as_nested_set_options[:left_column]}")
end

def leaves
  acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:right_column]} = #{acts_as_nested_set_options[:left_column]} + 1)", :order => "#{acts_as_nested_set_options[:left_column]}")
end

Or if you're savvy you can just apply the patch I created that includes these methods along with documentation and tests:

  • download the patch
  • move the patch to the root of your BetterNestedSet plugin
  • patch -p0 < leaves_and_parents_class_methods.patch

I've also added the patch as an enhancement to the BetterNestedSet trac.

On a recent project when I was using the BetterNestedSet plugin to manage a large hierarchal set of data, I encountered a problem that required me to find all of the items in a nested set that had children and those that didn't. In nested set terms I wanted: all 'parent' nodes and all 'leaf' nodes that exist within the 'tree'.

If you want to do this through the current BetterNestedSet interface you might be tempted to do something like this:

Comment | 

Campfire SVN and email notification

Mini

by Dave Naffis

Here's a quick way to add Subversion notification for Campfire using Tinder.

Create svn-campfire.rb with the correct username and password:

#!/usr/local/bin/ruby
require 'rubygems'
require 'tinder'

svnlook = "/usr/local/bin/svnlook"


campfire = Tinder::Campfire.new 'campfiresubdomain'
campfire.login 'user@example.com', 'password'
room = campfire.find_room_by_name('room name')
room.join

if ARGV.size > 1
  revision = ARGV[1]
  path = ARGV[0]
  # we're using this for multiple svn repos so parse the project name from the path
  project = ARGV[0].gsub("/home/user/svn/", '')
  
  author = `#{svnlook} author -r #{revision} #{path}`
  paths  = `#{svnlook} changed -r #{revision} #{path}`   
  log    = `#{svnlook} log -r #{revision} #{path}`
  message = [log,paths].join("\n").strip
  url = "Changeset \##{revision} by #{author} (http://trac.domain.com/trac/#{project}/changeset/#{revision})"

  room.speak(url)
  room.paste(message)
else
  room.speak(ARGV[0])
end

room.leave

Add this to your SVN post-commit hook:

/usr/local/bin/ruby /path/to/svn-campfire.rb "$1" "$2"

Here's a quick way to send emails to campfire. Create an email address to use for sending messages to campfire and then create mailer-campfire.rb with your domain, usernames and passwords:

#!/usr/local/bin/ruby
require 'rubygems'
require 'action_mailer'
require 'tinder'
require 'net/pop'

# setup an email address to use for campfire
Net::POP3.delete_all("domain.com", nil, "user+domain.com", "password") do |m|
  campfire = Tinder::Campfire.new 'campfiresubdomain'
  campfire.login 'user@example.com', 'password'
  room = campfire.find_room_by_name('room name')
  room.join

  begin
    message = TMail::Mail.parse(m.pop)
    
    subject = message.subject if message.subject
    sender = message.from.first if message.from
    body = message.body if message.body
    
    room.speak("I've received an email from #{sender} with the subject '#{subject}'")
    room.paste(body)                
  rescue Exception => e
  end        
    
  room.leave
end

Then create a cron job to fire this off every minute:

* * * * * /usr/local/bin/ruby /home/path/to/mailer-campfire.rb

We also use it to remind us of daily standups:

#!/usr/local/bin/ruby
require 'rubygems'
require 'tinder'

campfire = Tinder::Campfire.new 'campfiresubdomain'
campfire.login 'user@domain.com', 'password'
room = campfire.find_room_by_name('room name')
room.join
room.paste("Time for daily standup.\nWhat did you do yesterday? What are you doing today? Any roadblocks?")    
room.leave

Our cron job fires it off every weekday at 2pm.:

0 14 * * 1-5 /usr/local/bin/ruby /home/path/to/status-campfire.rb

Next step, create a Jabber gateway for Campfire using Tinder.

Comment | 

Bending Ruby (Part I) - An User-friendly Hash using method_missing

Mini

by Pradeep Elankumaran

There’s been a lot of talk about method_missing lately. Let’s do a little example that leverages this freaky but neat little method in our quest to bend Rails to our will. The following code is a handy trick that lets you access key values in a Hash as regular class methods.

class Hash
  def method_missing(method, *params)
    method = method.to_sym
    return self[method] if self.keys.collect(&:to_sym).include?(method)
    super
  end
end

If you have a key called :name, then my_hash[:name] and my_hash.name will now give the same result. If you call some key that doesn’t exist, then the super call tells Object to throw a generic NoMethodError. Neat, no?

P.S. the collect(&:tosym)_ shortcut used above actually evaluates to collect{|x| x.tosym}_ in Rails. This functionality is not available in Ruby, but it can easily be replicated by overriding the Symbol class, like so:

class Symbol
  def to_proc(*args)
    Proc.new { |*args| args.shift.__send__(self, *args) }
  end
end

Bending Ruby will be a series of posts that will build on one another.

Comment | 

Customized page.* methods for Rails' RJS Templates

Mini

by Pradeep Elankumaran

So you want to clear your live search fields the moment someone clicks on a result. Here’s a little bit of code that will let you do so in your RJS template:

page.replace_html 'search_results', ''
page[:live_search_bar].value = ''
</filter:jsode>

However, suppose you want to use this same live search clearing scheme over multiple controllers. You can either do re-use the above code for each respective controller method, or you can write the following in your RJS views, thereby DRY-ing up your code:

<pre name="code" class="ruby">
page.clear_my_live_search

How, oh how ever do I implement this for my app? Well, this works because in Ruby, it’s quite easy to add or override methods to any class or module. So let’s hack into ActionView, which is the part of Rails that gives you all those neat-o functions in your views (for example: the much-loved link_to).

The trick to overriding Rails code is to always have a copy of Edge Rails checked out to refer to, so you can get the namespace right. For this example, we have established that we want to extend the page.* methods that are prevalent through RJS templates and “render :update” calls. First we need to find out where the code lives. Let’s run a text search on our edge rails copy for ‘insert_html’, which is a commonly used RJS method. We then find out that it’s at _action_pack/lib/action_view/helpers/prototype_helper.rb_. Well, this is a start!

Next, we look at the namespace of the code in _prototype_helper.rb_, and try to find insert_html. We then see that it’s nested like so:

module ActionView
  module Helpers
    module PrototypeHelper
      class JavascriptGenerator
        module GeneratorMethods
           def insert_html
              # .... code ...
           end
         end
      end
   end
end

Now, in lib/actionviewhacks.rb_, copy this namespace and replace the _insert_html_ method with a method of your choice:

module ActionView
  module Helpers
    module PrototypeHelper
      class JavascriptGenerator
        module GeneratorMethods
           
           def clear_my_live_search
              page.replace_html 'search_results', ''
              page[:live_search_bar].value = ''
           end

         end
      end
   end
end

Next, update your environment.rb file by adding this somewhere:

require ‘actionview_hacks’

That’s it! You can now call page.clearmy_live_search_ from any RJS template or render :update method. You can also use _update_page_tag_ to insert the page. methods we just generated into your views as javascript.

Also, this example is quite basic. Some might call it overkill to override Rails helpers to get this running. Another good way of doing the same is to define a new method in one of your helpers that uses update_page, like so:

module LiveSearchHelper
  def clear_my_live_search
    update_page do |page|
      page.replace_html 'search_results', ''
      page[:live_search_bar].value = ''
    end
  end
end

You can then use this helper all over the place, too.

This article barely touches the surface of what’s possible when extending Rails — most existing Rails plugins probably got their start by practically the same process as what we followed here.

Comment | 

Words we've written view all blog posts »

Featured Article

Intridea at Lonestar Ruby Conference

by Renae Bair on August 18, 2010

For the third straight year in a row, senior-level developers from the Intridea team will be at the Lonestar Ruby Conference, on Thursday, August 26th, teaching students about Ruby. Students attending the Ruby Intrigue class will work with our Director of Mobile Development, Brendan Lim, our Director of Development, Adam Bair, and our Director of Research and Development, Pradeep Elankumaran. Continue reading »

Recent Blog Posts

FlockFeeds Launches From Node Knockout

by Intridea on August 30, 2010

Using NPM with Heroku Node.js

by Michael Bleigh on August 24, 2010

Fixing Common Bundler Problems

by Jerry Cheung on August 23, 2010