Shoulda has long been available as a plugin. It's core was yanked out at some point, and made available as a gem. Unfortunately, the codebases diverged, with main development occurring in the plugin.
What was once was divided is now united, as of this day. Shoulda 2.0.0. Check it:
$ gem install thoughtbot-shoulda
Nothing new there, but you can use this gem in a Rails app:
# in config/environment.rb
Rails::Initializer.run do |config|
config.gem 'thoughtbot-shoulda', :lib => 'shoulda/rails', :source => 'http://gems.github.com'
end
Using gems instead of plugins isn't perfect though, specifically, rake tasks don't get loaded yet. Hopefully that will be fixed eventually, but in the mean time, you can do:
# in Rakefile
begin require 'shoulda/tasks' rescue LoadError end
You can also use this gem in any non-Rails app. In your test_helper.rb, you'd just do something like:
require 'shoulda'
So what else is new? I'm not sure exactly what was in the last release, so I'll leave that for a more official announcement.
factory_girl is pretty sweet. I'm not going over to rehash its awesomeness, but you can check out its website.
Not that it was difficult to use with Rails, but now it's even easier.
I present to you the-oh-so-creatively-named factory_girl_on_rails.
Install it
script/plugin install git://github.com/technicalpickles/factory_girl_on_rails.git
What it does
This plugin allows you to place factory definitions in test/factories, and the plugin will automatically load them.
Additionally, it provides a simple generator for creating new factories:
./script/generate factory account
This creates an Account factory: test/factories/account_factory.rb
./script/generate factory post title:string body:text published:boolean
This creates a Post factory with a string title, text body, and published flag.
The source
It lives on GitHub: technicalpickles/factorygirlon_rails
Summary
Overall, this plugin doesn't do a whole lot, but I had to do this kind of thing by hand on enough projects that I figured it was worth it.
I recently decided to extract some plugins, in an effort to clean up the codebase for my blog.
The first thing I tackled was generation of HTML from my Post model.
In the beginning...
Here's the starting point for my model:
class Post < ActiveRecord::Base
# --- SNIP ---
# TODO move into own file... and plugin?
def self.validates_markdown(*attrs)
validates_each(*attrs) do |record, attr, value|
begin
BlueCloth.new(value).to_html unless value.nil?
rescue BlueCloth::FormatError => e
errors.add attr, "has #{e}"
end
end
end
validates_presence_of :content
validates_markdown :content
before_save :cache_content
# Use BlueCloth to generate HTML ahead of time.
def cache_content
html = BlueCloth.new(self.content).to_html
self.cached_content = html
end
# --- SNIP ---
end
validates_markdown really doesn't belong here
- Nothing particularly interesting is happening, but the lines of code start to add up
Let's look at the partial for Post.
%div{ :id => dom_id(post), :class => dom_class(post) }
%h2.title= link_to(post.title, post)
.content~ post.cached_content
- Eh, nothing particuarly interesting
Goals
- One-liner for specifying markup, similar to
has_many or acts_as_taggable
- Optionally require the markup
- Optionally cache the markup
- Allow for different syntaxes
A whole new look on things
I was able to extract the logic out of my model and hit all of these goals.
The refactored model:
class Post < ActiveRecord::Base
# --- SNIP ---
has_markup :content, :required => true, :cache_html => true
# --- SNIP ---
end
And the view is more or less the same:
%div{ :id => dom_id(post), :class => dom_class(post) }
%h2.title= link_to(post.title, post)
.content~ post.cached_content_html
Thoughts
- Plugins are really easy to make
- Plugins can pull a good amount of code out of your model, which results in it being more readable
- I think I finally understand the difference between include and extend
Get it
If you're interested in trying this plugin, it is hosted on GitHub. You can install it by with:
script/plugin install git://github.com/technicalpickles/has_markup.git