Skip to main content

Mobomo webinars-now on demand! | learn more.

So many of components we build into our web applications have a grain of an extractable element, a standardization waiting to happen. Starting today, I am putting together a “Standard UI Kit” for all of the tools that help me build interfaces faster. Together, they are called the UberKit. This week, the first segment is coming: UberMenus.

UberMenu: Abstract Menu Generation

Most people who build interfaces will build their menus with the same structure over and over. I finally took the time to abstract this out into a single helper that can pretty much serve all of my navigational needs. Here’s how you use it in a view:

<% ubermenu do |m| %>   <% m.action 'Home', '/' %>   <% m.action 'Users', users_path %>   <% m.action 'Log Out', logout_path, :class => "special" %> <% end %>

Becomes this HTML (assuming you’re at the document root):

<ul>   <li class="first current first_current"><a href="/">Home</a></li>   <li><a href="/users">Users</a></li>   <li class="special last"><a href="/logout">Log Out</a></li> </ul>

The current class will automatically be set on whichever page responds to the built-in Rails helper current_page? and the action syntax behaves just like a link_to. If a given action has multiple classes, they will also be joined with underscores as an additional class for browsers that do not support multiple class declarations. But in addition to easily creating simple menus, you can also easily generate multi-level navigation menus:

<% ubermenu 'nav' do |m| %>   <% m.action 'Home', home_path %>   <% m.submenu 'Services', services_path do |s| %>     <% s.action 'Service A', service_path('a') %>     <% s.action 'Service B', service_path('b') %>   <% end %> <% end %>

Which will become this HTML:

<ul id='nav'>   <li class='first current first_current'><a href="/">Home</a></li>   <li class='last'><a href="/services">Services</a>     <ul>       <li><a href="/services/a">Service A</a></li>       <li><a href="/services/b">Service B</a></li>     </ul>   </li> </ul>

Installation

UberKit is available both as a gem and a traditional plugin. For the gem version, add this to your environment.rb:

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

Or as a traditional plugin:

script/plugin install git://github.com/mbleigh/uberkit.git

Future of the UberKit

While UberMenu is a useful tool, the UberKit will continue to grow over time, so stay tuned for additions (next on the slate: UberForm). It may also grow to include some common styles and javascripts that can be used in conjunction with the helpers to provide an even easier track to a full-fledged UI.

Resources

As always, the source is on GitHub and there is an Acts As Community Profile available as well. If you have any problems with it or would like to request new features, enter them on the Lighthouse project.

Categories
Author

The discussion around HTML 5 has been heating up recently, with people advocating to get it finalized and implemented sooner rather than later (and lamenting the ulterior motives of major browser vendors in lobbying for specs). I simply can’t get passionate about this fight, much as I’ve tried. While some of the things that HTML 5 offers will certainly be a boon for web developers, by and large the issues that it addresses (in terms of interactivity) are surmountable simply by using the excellent Javascript libraries we’ve all become dependent upon. The next version of the CSS specification, however, is an entirely different story.

I recently started a new project and as an experiment decided to play with using the non-final border-radius implementations available in Firefox and Safari. After using it for about 15 minutes, I decided that I would simply forgo rounded corners in the interface for Internet Explorer. After using it for three days, I am wondering why every designer and developer on the internet isn’t simultaneously demanding immediate forced adoption of CSS3.

Styling is Fun Again

Our interfaces and style tastes have grown much more complex as the web has grown up, but the tools we use to implement those styles haven’t been keeping up. It shouldn’t feel like a trip to the dentist just to get a box to have some rounded edges. It shouldn’t be a nightmare to try to use translucent pngs for overlays (admittedly this has nothing to do with CSS3 and everything to do with IE6, the browser that won’t die no matter how much we pray).

I can tell you that styling on the edge doesn’t just feel good, it feels amazing. I’m able to implement in a few seconds what I might otherwise spend three hours styling while polluting my markup with hack tags.

Rounded Corners: Nemesis of Designers Everywhere

There is no good way to make rounded corners. The javascript libraries are buggy, images are limited in practicality, and getting it just right in all browsers is downright painful and usually ends up with markup something like this (and a whole mess of CSS to go with):

<div class='rounded'>   <div class='tl'>     <div class='tr'>       <div class='bl'>         <div class='br'>           So much for semantics...         </div>       </div>     </div>   </div> </div>

In the CSS3 specification, the same effect is achievable like so:

.rounded { border-radius: 10px; }

But it’s not just a convenient way to shortcut the hacks to which we’ve all grown accustomed, it opens up entirely new possibilities for design that would simply not be worth the effort to hack without it.

Lead By Example

Let me explain what I mean by example. Form design has always been one of the trickiest parts of web design, what can we do with a little CSS 3 magic? Let’s say we have a simple form that takes a person’s name:

<form id='sample_form'>   <label for="name">First Name:</label>   <input type='text' name="name" id="name"/><br/>      <label for="name">Last Name:</label>   <input type='text' name="name" id="name"/><br/>      <button type="submit">Submit</button> </form>

Simple enough, this turns out looking something like this:

Now we can add some standard CSS to make it look a little more acceptable:

label {   display: block;   float: left;   width: 100px;   font-weight: bold;   padding: 4px 5px;   font-family: Verdana, sans-serif;   font-size: 12px;   margin-bottom: 5px;   clear: both;   text-align: right; }  input {   font-size: 12px;   margin-bottom: 5px; } button {   margin-left: 115px;   margin-top: 10px; }

And our result is a perfectly usable form:

But what if we use just a taste of what CSS3 has to offer? We can make a form that looks completely unique without using a single image:

label {   display: block;   float: left;   width: 100px;   padding: 4px 5px;   border: 2px solid #037;   background: #06a;   color: #fff;   font-family: Verdana, sans-serif;    font-size: 12px;   margin-bottom: 5px;   font-weight: bold;   clear: both;   text-align: right;   border-radius: 13px;   border-top-right-radius: 0px;   border-bottom-right-radius: 0px; }  input {   background: #fff;   border: 2px solid #8ac;   border-left: 0px;   padding: 5px 5px;   margin-top: 0;   margin-bottom: 5px;   margin-left: 0;   border-radius: 5px;   top-left-radius: 0px;   border-bottom-left-radius: 0px; }  button {   background: #080;   color: #fff;   border: 2px solid #060;   font-size: 12px;   font-weight: bold;   margin-left: 112px;   padding: 5px 10px;   border-radius: 13px; }

It’s a hefty chunk of code, but anyone experienced in writing CSS can knock something like that out in about five minutes. The result is well worth it:

This kind of styling opens up with the application of just a single new attribute from the CSS3 draft specifications. Designers have had to hack, cheat, and wrangle every semi-complex interface that has been developed in the last 5 years thanks to the limitations of CSS (and more specifically the limitations of Internet Explorer), but it doesn’t have to stay that way forever.

State of the Browser

The complete CSS3 spec is not coming to a browser near you any time soon (more accurately not all browsers), and that’s a real shame. It brings to the table powerful new tools that can really enable the kind of semantic markup that we all wish was possible with today’s browsers. Rounded corners are just the “tip of the iceberg”; once CSS3 sees widespread adoption, interface design will take a leap forward unlike any it has seen before.

In the meantime, keep an eye out on the WebKit Nightlies for cutting edge CSS implementations (just added: CSS Variables). Five years from now we’ll look at the troubles we used to have and laugh. Until then, a person can dream…

Categories
Author

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.

Categories
Author

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.

Categories
Author

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!

Categories
Author

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.

Categories
Author

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.

Categories
Author

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.

Categories
Author

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.

Categories
Tags
Author

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?

Categories
Author
Subscribe to