Announcing the CrowdSound July 2008 Release

Intridea is proud to announce the July 2008 release of CrowdSound, the social feedback tool that opens up new lines of communication between you and your customers. The social feedback tool allows enterprise websites and social networking sites to gather, organize and respond to suggestions from their customers—for just $10 per month. Because CrowdSound requires only minimal Web developer knowledge to implement, businesses of all sizes can quickly realize the power of interactive, Web-based customer feedback.


The latest release of CrowdSound has many new much-requested features:

* Customize the widget's colors and look and feel
* A hosted website in addition to the widget
* Custom suggestion buckets
* Private suggestions for sensitive topics
* SSL encryption
* iPhone integration
* User-selectable, customizable categories for each suggestion
* Profanity filtering to focus on constructive criticism
* ...and many more!

Using CrowdSound, companies can open a direct line of communications with customers via the Web—transparently gathering their suggestions without forcing them to navigate away from their page. The standards-based, highly customizable tool seamlessly integrates with an enterprise website or social networking site while providing a tailored look-and-feel that reinforces the company brand.

For additional details and to try it out, visit CrowdSound.com

Share:

Comment on this post (2 comments)


RankFu: Expressive user roles for Rails

Posted by on June 30th, 2008.

Almost every Rails developer has written an app with more than one user role, but when is_admin? isn’t enough, where do you go? RankFu aims to solve this by giving you a rich toolset for roles. Now it’s free to allow users to have more than one role, so you can have modifiers such as ‘Trusted’ and ‘New’ trivially. It’s also easy to have sets of roles, with administrators outranking moderators. Sets are optional though, so you’re free not to put Telephone Sanitizers in one due to their obvious lack of importance.

Throughout this piece, I’ll be talking about the ubiquitous User model, but you can use RankFu with any model you wish to.

Rankin’ Fu

When you install RankFu, you can add several new methods to your models:


User#has_role? 
User#has_role
User#"#{role}?" 
User#"#{role}_exactly?"    #This forces an exact comparison, useful if you want to test for a role which has a superset (e.g. moderators and  administrators)
User#"make_#{role}          
User#"remove_#{role}" 
User#rank                #Returns a string listing all roles, modifiers first eg: "Trusted Administrator" 
User#roles                #Returns an array of role names.

There is also some sugar for disabling users, to make your code more readable. These examples assume the existence of role with :disabled as its key:


User#disable_user 
User#enable_user
User#enabled?                       

Building on this, you can easily clean up your views. I DRY’d up many instances login check logic.


def logged_in_as_mod?
def logged_in_as?(user)  
def logged_in_as_friend_of?(user)  
def logged_in_as_or_as_friend_of?(user)   

There might have been a few others, but I don’t want to give any more ammunition to those who accuse me of pedantry.

InstallationFu

The easiest way to install is as a standard Rails plugin:

script/plugin install git://github.com/mjt/rank_fu.git

After installing this plugin, you’ll want to start by performing some admin:


script/generate rank_fu user
script/generate rank_fu roles         #create migration for roles 

After that, you’ll probably want to add roles to your user model, so just add this line:

knows_rank_fu

Then you need to create some roles. I suggest using the excellent Seed Fu plugin so you can do something like this:


Role.destroy_all
roles = [ {:id => 1, :key => "root",      :name=> "Superuser", :value => 2**22, :set => 1},
          {:id => 2, :key => "admin",     :name=> "Administrator", :value => 2**21, :set => 1},
          {:id => 3, :key => "moderator", :name=> "Editor", :value => 2**20, :set => 1},     
          {:id => 5, :key => "member",    :name=> "Member", :value => 2**10, :is_default => true}]

roles.each do |role|                          
  Role.create role
end

What’s going on here?

Not much.

Internally, bitwise arithmetic is used to store each model’s role-state. Once a model knows RankFu, you can assign and remove roles freely, knowing that RankFu is a good citizen and uses update_attribute internally.

You may also find that you can reduce your use of STI by separating users by roles.

Please feel free to leave any feedback in the comments.

Share:

Comment on this post (1 comment)


Tracking Your Brand With Summize

Posted by on June 27th, 2008.

If you have a product in the technology sphere, chances are people are going to be talking about it on Twitter. Given the outspoken nature of most Twitter users, it’s probably a good idea to keep track of what people are saying about your company, product, or yourself. Luckily, Summize, a Twitter search engine, gives you the all tools you need to easily track any term you want to remember on Twitter.

It’s as Easy as One, Two. No Three Required

Just go to Summize and make a query for the brand or product you want to track, joining all of the possible spellings of that product with “OR”s (case does not matter, so MyProduct and myproduct are the same).

Now in the search results, all you have to do is click on the “Feed for this query” button and subscribe to it in your favorite RSS reader. You will automatically be updated any time anyone in the Twitterverse talks about your terms!


On the go? Summizer to the rescue!

Jon Maddox of Mustache, Inc. has created a great tool for iPhone users called Summizer. It lets you track terms via Summize with a simple interface and remembers your terms for your next visit. So if you are more likely to poke around on your iPhone than your RSS feeds, that may be a better solution for you.

Knowing what people are saying on Twitter is a valuable way to hear opinions of some of the tech world’s earliest adopters, and also gives you a chance to respond to criticisms and frustrations. Take the couple of minutes to set up your product’s feed and you will not regret it!

Share:

Comment on this post (0 comments)


Using RSpec and Autotest While Writing Rails Plugins

Posted by on June 25th, 2008.

RSpec is a great tool that has come to replace Test::Unit for many Rails developers. Autotest makes it go even faster, and has become an indispensable part of my development environment. However, it has always been somewhat-to-extremely difficult to use RSpec when developing Rails plugins. In this post I will walk through step-by-step how to get RSpec and Autotest working with your plugin.

This plugin is assuming that you are running Rails >= 2.1 and have already installed RSpec and RSpec::Rails as plugins in your Rails project like so:

script/plugin install git://github.com/dchelimsky/rspec.git
script/plugin install git://github.com/dchelimsky/rspec-rails.git

And also gotten RSpec up and running by calling script/generate rspec.

Generate It

Luckily, I wasn’t the first person who ever wanted to create a plugin that was tested with RSpec. The Rspec Plugin Generator will do most of the heavy lifting for us when we start out. Just install it like so:

script/plugin install git://github.com/pat-maddox/rspec-plugin-generator.git

And you’re ready to get started. I’m assuming here that this is a brand new plugin, if it’s already in development you may need to run this in a fresh directory and then copy/paste files as needed to glue it together. Let’s say I’m writing a plugin called new_fu. I can generate an RSpec-ready plugin simply by calling:

script/generate rspec_plugin new_fu

This will generate the standard plugin structure as well as some extra files:

create  vendor/plugins/new_fu/spec
create  vendor/plugins/new_fu/spec/spec_helper.rb
create  vendor/plugins/new_fu/spec/new_fu_spec.rb

You can take a look at these to see how they work, but pretty simply they hook your plugin up so that it can be run with rake spec:plugins. Let’s add a simple example to our new_fu_spec.rb file:

require File.dirname(__FILE__) + '/spec_helper'

describe "NewFu" do
  it "should have a pending spec" 
end

Now if you run rake spec:plugins you should see one pending spec. Congratulations, your plugin is now running on RSpec!

Autotest Like a Champ

Ok, so now we’re up and running with RSpec on our plugin. That’s great, but if you have several plugins in the same Rails app that all have specs, it starts to get messy when you run that rake spec:plugins. Not to mention how long it takes between runs! We need to get an autotest setup like we have for our main Rails app!

I struggled with getting this to work for a long time, so thanks to this post on Rails Symphonies for finally pointing me in the right direction. First we need to create an autotest/discover.rb file in our plugin’s lib directory. In that file, put this code:

$:.push(File.join(File.dirname(__FILE__), %w[.. .. rspec]))  

Autotest.add_discovery do  
  "rspec" 
end

This gets us almost exactly where we want to be. However, the first time I ran it I had two problems: some specs that I had written were strangely failing, and it wasn’t in color or following the rest of my spec.opts preferences from my main app!

To remedy this, we need a spec.opts in the spec directory of the plugin. You can either copy and paste it in from your Rails app (my recommendation if you are publishing your plugin) or you can just create a softlink back to it:

ln -s ../../../../spec/spec.opts spec.opts

That’s it! Now if you run autotest you should be running all of the specs for your plugin just as you would if you were running them for your app. Note that this doesn’t hook in to your app’s autotest, which may be desirable or undesirable to your specific needs.

Share:

Comment on this post (4 comments)


SubdomainFu: A New Way To Tame The Subdomain

An extremely common practice for Rails applications is to provide keyed access through subdomains (i.e. http://someaccount.awesomeapp.com/). However, there has never been a real unified convention for handling this functionality. DHH’s Account Location works for some circumstances but is more tailored for a Basecamp domain model (i.e. the app is on a separate domain from all other functionality, so you can always expect a subdomain) than the more common usage of one domain only.

SubdomainFu aims to provide a simple, generic toolset for dealing with subdomains in Rails applications. Rather than tie the functionality to something specific like an account, SubdomainFu simply provides a foundation upon which any subdomain-keyed system can easily be built.

Usage Fu

SubdomainFu works by riding on top of the URL Rewriting engine provided with Rails. This way you can use it anywhere you normally generate URLs: through url_for, in named routes, and in resources-based routes. There’s a small amount of configuration that is needed to get you running (though the defaults should work for most).

To set it up, you can modify any of these settings (the defaults are shown):

# in environment.rb

# These are the sizes of the domain (i.e. 0 for localhost, 1 for something.com)
# for each of your environments
SubdomainFu.tld_sizes = { :development => 0,
                          :test => 0,
                          :production => 1 }

# These are the subdomains that will be equivalent to no subdomain
SubdomainFu.mirrors = ["www"]

# This is the "preferred mirror" if you would rather show this subdomain
# in the URL than no subdomain at all.
SubdomainFu.preferred_mirror = "www"

Now when you’re in your application, you will have access to two useful features: a current_subdomain method and the URL Rewriting helpers. The current_subdomain method will give you the current subdomain or return nil if there is no subdomain or the current subdomain is a mirror:

# http://some_subdomain.myapp.com/
current_subdomain # => "some_subdomain" 

# http://www.myapp.com/ or http://myapp.com/
current_subdomain # => nil

# http://some.subdomain.myapp.com
current_subdomain # => "some.subdomain"

The URL rewriting features of SubdomainFu come through a :subdomain option passed to any URL generating method. Here are some examples (in these examples, the current page is considered to be ‘http://intridea.com/’):

url_for(:controller => "my_controller", 
  :action => "my_action", 
  :subdomain => "awesome") # => http://awesome.intridea.com/my_controller/my_action

users_url(:subdomain => false)  # => http://intridea.com/users

# The full URL will be generated if the subdomain is not the same as the
# current subdomain, regardless of whether _path or _url is used.
users_path(:subdomain => "fun") # => http://fun.intridea.com/users
users_path(:subdomain => false) # => /users

While this is just a simple set of tools, it can allow the easy creation of powerful subdomain-using tools. Note that the easiest way to locally test multiple subdomains on your app is to edit /etc/hosts and add subdomains like so:

127.0.0.1    localhost subdomain1.localhost subdomain2.localhost www.localhost

Adding an entry for each subdomain you want to use locally. Then you need to flush your local DNS cache to make sure your changes are picked up:

sudo dscacheutil -flushcache

Installation

SubdomainFu is available both as a traditional plugin and as a GemPlugin for Rails 2.1 and later. For a traditional plugin, install like so:

script/plugin install git://github.com/mbleigh/subdomain-fu.git

For a GemPlugin, add this dependency to your environment.rb:

config.gem 'mbleigh-subdomain-fu', :source => "http://gems.github.com/", :lib => "subdomain-fu"

Implementing A Simple Account Key System

Let’s take this functionality and implement a simple account-key system based off of the subdomain. We’ll start with some controller code (assuming that we have an Account model with a ‘subdomain’ field):

class ApplicationController < ActionController::Base
  protected

  # Will either fetch the current account or return nil if none is found
  def current_account
    @account ||= Account.find_by_subdomain(current_subdomain)
  end
  # Make this method visible to views as well
  helper_method :current_account

  # This is a before_filter we'll use in other controllers
  def account_required
    unless current_account
      flash[:error] = "Could not find the account '#{current_subdomain}'" 
      redirect_to :controller => "site", :action => "home", :subdomain => false
    end
  end
end

That’s really all we need for a basic setup, now let’s say we have a ProjectsController that you must specify an account to access:

class ProjectsController < ApplicationController
  # Redirect users away if no subdomain is specified
  before_filter :account_required
end

There’s lots more you can do with the plugin, but this is a simple use case that everyone can relate to.

Resources and Plans

A feature that I hoped would make it to the first release of SubdomainFu but is now a planned feature is subdomain-aware routing so that you can add conditional subdomain routes to your routes.rb file. Keep an eye out for more on that in the future.

In the meantime, the project will live at its home on Acts As Community for intermittent updates, is available on GitHub as always, and bugs/feature requests may be passed on through the Lighthouse.

Share:

Comment on this post (25 comments)


We "Cheat" And So Should You

Posted by on June 20th, 2008.

I’m the kind of guy who has a tendency to memorize where to find information instead of the information itself. It usually goes something like this:

google -> foo -> 3rd link -> middle of the page -> oh yeah -> profit$
google -> bar -> 2nd page -> 5th link -> sidebar 2nd link -> ahh yeah -> profit$

I love compulsive behavior as much as the next guy – but this does get old after a while, even looking up obscure Ruby methods and Bash commands to satisfy my questionable motivations. You can break the cycle; you can cheat the system.

Err the Cheat

‘cheat’ is a small utility app created by Chris Wanstrath (of Err and GitHub fame) that is basically a command line interface to a simple wiki. It was announced over a year ago and is built on _why’s excellent Camping ‘microframework’ with a YAML backend.

Anyone can create, edit, and modify cheat pages and anyone can call them up via the command line tool like so:

cheat foo

Installation

‘cheat’ is a gem and can be installed thusly:

sudo gem install cheat

You can check to make sure that everything is copacetic by issuing:

cheat cheat

If this works, you’re cheating.

Cheating

The first thing you should do is check out the all of the available cheat sheets. If there’s something you need that’s not in the list – by all means create your own, it benefits everyone (...or just you depending on how obscure the information is).

You can list the available sheets:

cheat sheets

Some sheets of interest include: sed, awk, git, git-svn, vim, and of course acts_as_taggable_on.

You can call up any of the sheets by name using the cheat command:

cheat 'foo_sheet_title'

Note: each time you access a sheet for the first time it gets cached locally in a .cheat folder in your home folder (This is on OSX, this will still work on windows, but you need to have a HOMEDRIVE or HOMEPATH environment variable set).

Cheated

You can be compulsive and efficient at the same time – thanks Cheat! Instead of hitting google everytime you need that same obscure ruby/awk/sed/vi reference—just cheat and the system goes from:

google -> ??? -> profit$

to:

cheat foo -> profit$

Ditch the ambiguous question marks and accelerate your profit$, cheat.

“Please be kind to the wiki. And, uh, keep the cheat sheets Ruby-centric. Bash is okay but Python is banned.” – Chris Wanstrath

Share:

Comment on this post (0 comments)


Going Rogue with git-svn on OS X

Posted by on June 18th, 2008.

I’m sure that most of you have discovered that Git and github are the new hotness in source control. Once you go Git… well, you get the point. But what happens if you DO have to go back to Subversion? Not to worry, git still has you covered in the form of git-svn.

The git-svn command allows you to interact with a subversion repository through a git front-end on your local box. You get all of the fun branching and general git-ness without pain of svn. Even the mythical developer on a plane can make commits without a network connection!

Preparing the Goods

If you already have git and svn installed you might notice that you have a bunch of git commands available—although the all-important git-svn may be missing. If this is the case, the likely reason is that you are missing the perl bindings for subversion. This is okay and is easily fixed via macports. The first thing you need to do is uninstall git-core:

sudo port uninstall git-core

Then you need to reinstall it with svn support (which will setup the svn perl bindings automatically):

sudo port install git-core +svn

After this finishes (takes a few mins), the ‘git-svn’ command should be a available.

Going Rogue

If your project is stuck in svn purgatory; you can still use the new hotness while it readies itself for the coming liberation. The first thing you need to do is smuggle the code out of svn and into a local git repository:

git-svn clone http://svn.foo.org/project/trunk

Okay, now this is going to take a while. Git is going to build a local git repo from scratch using each revision starting out at revision #1. If your svn repo has a bunch of commits (1000+) it’s going to take a while. It’s worth it though, trust me.

After this finishes you’ll have a fully functioning git repo on your box that is connected to your svn repository. The one thing that clone doesn’t take care of for you is mirroring all of the svn:ignore stuff. You can do this two ways:

Stay completely rogue and keep the ignore files locally:
git-svn show-ignore >> .git/info/exclude
Help out your other git-svn comrades by committing a .gitignore file to the svn repo:
git-svn show-ignore >> .gitignore

The first one doesn’t touch the svn repo and will keep your git-svn usage under the radar. The second will add .gitignore to the svn repo and will only need to be done once. This can be useful if you’ll be busy converting others to the git-monster as the new recruits will have one less thing to worry about.

At this point you should have all of your local git commands available for your disposal.

Code Trafficking

You can work with your local git repo just as you would with a normal git repo. The usual suspects are there: ‘git commit’, ‘git branch’, and ‘git stash’ will all work as expected without touching the svn repository.

You can grab the latest changes from the svn repo by issuing:

git-svn rebase

This will pull all of your local changes out of the repo temporarily, pull down the latest changes from svn, merge them into your git repository, and then apply your stashed changes on the new ‘base’.

When it comes time to get your wares back into subversion you can use:

git-svn dcommit

This will take all of your local outstanding git commits and translate them each into a standard svn commit complete with message, one at a time. The other repo denizens will be none the wiser because when you issue a dcommit—you’re generating plain old svn commits.

Exit Strategy

Hopefully at this point your suffering has been alleviated, freeing you to champion an underground git movement in your team and repository.

You now have the real ultimate power at your fingertips; go forth and dominate… silently.

Share:

Comment on this post (2 comments)


Announcing the Badger Rails Plugin

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?

Share:

Comment on this post (2 comments)


Deploying your Rails applications with Phusion Passenger

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.

Share:

Comment on this post (1 comment)


GemPlugins: A Brief Introduction to the Future of Rails Plugins

Posted by on June 11th, 2008.

The new Gem Dependencies of Rails 2.1 give developers an easier-than-ever ability to keep track of and maintain the various library dependencies inherent with any project. However, a much-overlooked additional feature of the Gem Dependencies is the ability to package traditional Rails plugins as a gem and have them hooked in properly. This article is designed as an introduction to how to write and use plugins as gems in Rails projects.

The Basics

The basic method by which this is achievable is that any plugin included through a config.gem command will automatically have the gem-packed file rails/init.rb run upon Rails’s initialization. All it takes is a little bit of effort, and any Rails plugin can be packaged as a gem and easily depended upon through gem dependencies.

You may be wondering why this is a “big deal.” Plugins are already dead simple to install in Rails (and you can even script/plugin install straight from Git now!), why do we need GemPlugins? It’s simple, really: RubyGems are a rock-solid established way of easily distributing versioned reusable bits of code. Using gems for plugins allows for a greater standardization of the way in which plugins are maintained and distributed, as well as a simple path for version-locking to ensure compatibility with legacy code etc.

Another reason that GemPlugins are important is that they provide a level of abstraction from Rails: by releasing a gem rails/init.rb you could also use the same exact code to release a Merb plugin or any other framework that supports gemified add-ons. I think you will begin to see a number of cross-framework plugins be developed as Rails gets some company and shares alike.

Using a GemPlugin

First, let’s go through the process required to use an existing gem plugin. I’m going to be using my Acts As Taggable On plugin as an example throughout because I just recently went through the process of making it available as a gem.

First, you will need to include the dependency in your environment.rb file. I’m assuming here that most plugins are going to be hosted on GitHub, but the same should be true for any gem source.

# in environment.rb

config.gem "mbleigh-acts-as-taggable-on", :source => "http://gems.github.com", :lib => "acts-as-taggable-on"

This is the standard usage of gem dependencies, and for more info on this you can see Ryan Daigle’s post or watch the RailsCast on the subject. Now assuming that you don’t already have the gem in question installed, it’s simple to grab it:

rake gems:install

This will automatically install any gem dependencies in your project, and will tell you what’s happening the same as if you had run gem install from the command line.

That’s it! Once you have successfully installed the necessary gem, you can simply start up your Rails server and the plugin will be loaded and initialized as though it were living in your vendor/plugins directory.

Now that you know how to use a GemPlugin, I’ll show you how you can take an existing plugin and gemify it quickly and painlessly.

Making a GemPlugin

Let’s say I have a plugin called awesome_fu that lives on GitHub at mbleigh/awesome-fu. I’ve already released this plugin, it works great, and now I want to make it compatible with GemPlugins.

First, let’s create a gemspec called awesome-fu.gemspec in line with the requirements for the GitHub Gem Repository. In order to make the file list, I usually find it’s easiest to “find **” in the plugin directory, then copy it into TextMate, make the modifications I need for manifest (using a regular expression to quote each of the files), and saving it in the spec. If you have only a few files in your plugin, it may be easier just to add them by hand.

Next we need to add rails/init.rb. This is a little bit troublesome, because we still want our plugin to work if installed through the traditional method, so we also need init.rb to run the same code (this is automatically fine in edge Rails). What I did for my plugin is copy all of my init.rb code into rails/init.rb and then change init.rb to the following:

require File.dirname(__FILE__) + "/rails/init"

Now they both run the same code without any kind of replication, great! This means that now I have set up my plugin to work equally as a GemPlugin or a traditional plugin with just a couple minutes of work.

All that’s left to do is switch on the RubyGem setting for my GitHub project, update the README, and push! Now anyone will be able to easily require the plugin as a gem dependency and you will get all of the accolades associated with releasing your plugin the “new and hip” way.

Caveat Coder

The one problem with GemPlugins that I have run into is that if you unpack your gems using “rake gems:unpack” the rails/init.rb file is not run on initialization. This is a known issue that is supposed (?) to be resolved but I have still experienced this problem in my experiments. Hopefully this issue will be fully resolved in edge Rails soon and the glorious future of GemPlugins can begin.

Share:

Comment on this post (6 comments)


Acts As Taggable On Grows Up

Acts As Taggable On (original post here), the tagging plugin with custom tag contexts, has gathered up some great new features over the past weeks thanks to the efforts of the community as well as fellow Intrideans Pradeep Elankumaran and Brendan Lim. I just wanted to take this opportunity to go over some of what’s new and interesting in the world of acts_as_taggable_on.

Community Fixes

First, Peter Cooper was kind enough to submit a patch that allows acts_as_taggable_on to work with Rails 2.1’s named_scope when using find_options_for_tag_counts.

Secondly, the much requested support for Single Table Inheritance is finally in! It was just a matter of using a class inheritable attribute instead of a class instance variable, and big thanks to slainer68 for hunting that down and taking the time to submit a patch.

If there’s anything you’ve hacked on to Acts As Taggable On, I urge you to submit a patch to the Lighthouse Project. I try to get new patches integrated into the codebase as quickly as possible, so please do submit anything!

During the Community Code Drive at RailsConf two great features were added: taggers and related objects.

Taggers

Tags can now have ownership, allowing for such things as User-tracked tags and more. This was a requested feature and something that I’d been looking forward to myself. Here’s the usage:

class User < ActiveRecord::Base
  acts_as_tagger
end

class Photo < ActiveRecord::Base
  acts_as_taggable_on :locations
end

@some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations)
@some_user.owned_taggings
@some_user.owned_tags
@some_photo.locations_from(@some_user)

Find Related

Another request (and another great idea) is the ability to find related objects by similar tags. This is now available through the @object.find_related_on_tags syntax:

@bobby = User.find_by_name("Bobby")
@bobby.skill_list # => ["jogging", "diving"]

@frankie = User.find_by_name("Frankie")
@frankie.skill_list # => ["hacking"]

@tom = User.find_by_name("Tom")
@tom.skill_list # => ["hacking", "jogging", "diving"]

@tom.find_related_on_skills # => [<User name="Bobby">,<User name="Frankie">]
@bobby.find_related_on_skills # => [<User name="Tom">] 
@frankie.find_related_on_skills # => [<User name="Tom">] 

Gemified!

Acts As Taggable On now works as a GemPlugin in Rails. This is a new way (as of Rails 2.1) of distributing plugins as gems and having them still automatically link up and do their magic. To use it as a gem, add it to your config/environment.rb like so:

config.gem "mbleigh-acts-as-taggable-on", :source => "http://gems.github.com", :lib => "acts-as-taggable-on"

Now you should be able to get the latest version of the plugin just by running rake gems:install. However, this hasn’t been working for me so the alternative is just to install the gem directly:

gem install mbleigh-acts-as-taggable-on --source http://gems.github.com/

Now when you run your Rails app, even though it’s not in vendor/plugins it should be running! To make sure, look for this line on startup:

** acts_as_taggable_on: initialized properly

There are still a couple of issues outstanding in Rails regarding GemPlugins (if you unpack it, it will not run the initialization properly for some reason), but I wanted to give everyone the latest and greatest way to install the plugin possible. It will still work fine using the conventional methods as well.

Community and Future

I’ve been really happy with the response and support of the community, and I would like to do everything possible to cultivate future participation. To that end, I have created an Acts As Community Project for acts_as_taggable_on that will hopefully provide some casual communication about the project. Feel free to post on the wall or in the forums, and look out for additions soon.

Finally, the area of the plugin that still needs some work is tag caching. This is not a particular area of my expertise, so I’m hoping that someone from the community will write up some specs that flesh out the caching functionality in new and interesting ways.

Thanks for all of the patches, and I hope you continue to enjoy using Acts As Taggable On!

UPDATE (6/10/08): The improvements keep on rolling! After writing the post, I went off on a tangent and decided to make the plugin work both traditionally and as a gem. See more details above in the “Gemified” section.

Share:

Comment on this post (16 comments)


Announcing Fu-fu: The Profanity Filter for Rails

Posted by on June 6th, 2008.

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.

Share:

Comment on this post (7 comments)


RailsConf 2008 Recap

Posted by on June 4th, 2008.

We had a great time this year at RailsConf 2008 in Portland, Oregon. If you were there, we hope you had a chance to try out Yoga on Rails and hopefully you had a chance to stop by our booth to meet some of us. At our booth we were showing off some of our products, such as Acts As Community, CrowdSound, SocialSpring, Scalr, and MediaPlug. We even handed out a bunch of awesome Intridea t-shirts, which no swag-bag was complete without.

Day Before RailsConf 2008   RailsConf 2008
photo.jpg   RailsConf 2008

The Intridea team participated in the Community Code Drive on Thursday and worked on improving some of our open source plugins, such as Acts As Taggable On, SMS Fu, and Fu Fu. The rest of the conference was filled with informative talks from prominent members of the Rails and Ruby community. Even our very own Chris Selmer gave a talk on ‘How to Build an Rails App in 48 Hours’ with Josh Owens of the Web 2.0 Show.

RailsConf 2008  
RailsConf 2008   RailsConf 2008
RailsConf 2008   RailsConf 2008

Thanks goes out to everybody who stopped by our booth and everyone we met throughout the event. RailsConf 2008 was a blast and we can't wait until next year when we get to do it all over again.

Share:

Comment on this post (0 comments)


Spontaneous praise from our clients

Posted by on June 4th, 2008.

It's always a nice surprise when one of our client spontaneously praises Intridea. Recently, our friend and client T.J. of Freewebs.com wrote something nice on RailsConf Job Boards: "Intridea has been a joy to work with, working for them has got to be awesome!" Oh, by the way, we are looking for more Ruby Rock Stars!


RailsConf 2008


Congratulations to T.J. and the crew for raising 15 Million in Series A Funding for their new venture Social Gaming Network. I am jealous, he gets paid to write games!

Share:

Comment on this post (0 comments)