Oct 10, 2008
Bort was released recently. Peter Cooper speculated that "...it could well catch on as the de facto bare bones / generic Rails application". But, what about us non-RSpec users? There are dozens of us, I tell you. Dozens!
We build a lot of apps at GiraffeSoft — we love to experiment with whatever ideas excite us on any given day. We're all sick of editing restful_auth code, and moving tests over to Shoulda and the one assertion per test pattern. Bort doesn't suit our needs. So, blank was born.
Right now, it's pretty simple. It has authentication, and forgot password. That's about it. But, it's no biggie. Since blank creates your new app as a git repo that shares history with blank's repo, you can pull in changes we make at any time. So, when we finally get around to implementing openid support, you'll get it for free, if you start with blank.
Vendored
All of our standard tools (and rails) are vendored:
- active_presenter
- andand
- attribute_fu
- hoptoad
- mocha
- rake
- restful_authentication
- ruby-openid
- will_paginate
Installation
Installing blank is as easy as running a rake task. Except that blank uses thor instead, because it’s the new hotness, and it supports remote tasks.
Just install thor:
$ sudo gem install thor
…then install blank’s thor tasks:
$ thor install http://github.com/giraffesoft/blank/tree/master%2Fthorfiles%2Fblank.thor?raw=true
…then you’re ready to create a new app with blank:
$ thor blank:new_app the_name_of_my_app the@git.repo.it.will.live.in
That’s it! The thorfile will display a couple of rake notes where you should replace blank app with your app's name. Also, you'll want to fill in your hoptoad API key in config/initializers/hoptoad.rb.
If we improve the thor file, all you have to do is run:
$ thor update blank
before creating your next app, and you’ll get the changes automagically.
Development
All development will be done at the github repo. Fork away :)
Credits
Blank was created by me, with contributions from Daniel Haran.
Sep 03, 2008
I've been really bad about releasing new versions of r_c. The last version that I actually released officially was 0.2. Well, enough has happened that it's time to get official about things.
What's New
- Singleton controllers are now supported, thanks to Bartek Grinkiewicz (grin). Just inherit from ResourceController::Singleton, and you'll get a set of default action options that makes sense for a singleton controller. As always, there's more info in the RDoc.
- It's possible to properly inherit from r_c controllers now. However, you have to use the declaration syntax (calling resource_controller in your controller's class definition, rather than inheriting from RC::Base) to make it all work right.
- The flash helper now accepts a block, which means that you can interpolate in your flash messages. (i.e. create.flash { "#{@post.title} successfully created!" })
- Thanks to Jonathan Barket (his github is here), the scaffold_resource now generates RSpec specs, if RSpec is installed in your app.
- Lots of bugs and little issues were fixed.
- All r_c development is officially moved to github. Follow the repo here, if you're not already.
- From now on, r_c will only be supported as a gem dependency. Gem plugins are the new hotness; love them.
Contributors
Lots of awesome people contributed to this release.
Spree
As I mentioned before, Spree, the "Open Source Commerce Platform for Ruby on Rails", has moved to r_c. That also means that the Rails Envy guys' awesome new screencast site Envy Casts is powered by r_c. Since spree is open source, it makes a great example app for r_c. If you're looking for examples, the Spree source is a great place to start.
Get It
Add it as a gem dependency:
config.gem 'resource_controller'
Install it as a gem manually:
$ sudo gem install resource_controller
Or grab the source:
$ git clone git://github.com/giraffesoft/resource_controller.git
As always, the RDoc is available at http://docs.github.com/giraffesoft/resource_controller.
Aug 12, 2008
Spree wanted to become RESTful, so they chose resource_controller to help them keep DRY. At least some of those changes now seem to be merged in to master.
Jun 20, 2008
Jonathan Barket just sent me a patch that gets resource_controller's scaffold_resource generator to spit out RSpec specs! I quickly merged it in to master, and wanted to announce it to the world, since it's something I've been hoping to get added to the plugin for a while.
r_c's scaffold_resource generator now supports vanilla test/unit, Shoulda, and RSpec for tests, and erb, and haml for templating. It will sense which of those plugins or gems you have installed in your app, and generate accordingly — it's absolutely 0 configuration.
So, if you're an RSpec user, grab the latest master from github, and get generating! :)
May 08, 2008
A few weeks ago, Nate Wiger emailed me to ask whether I was interested in a patch for r_c. Evidently, it is possible to determine which controller actions need to be created by examining the routes that are pointing to it. Nate had also noticed that most controller actions follow a pattern:
- Load or build an object or a collection (i.e. Post.find(1) or Post.build(params[:post])).
- Optionally do something with the object(s) (i.e. @post.save).
- Optionally set the flash.
- Render a response.
Put those pieces together, and it's possible to create a controller abstraction that is aware of what's routed to it, and sets up a set of sensible defaults, even for custom actions. As you might have guessed, Nate and I have done exactly that.
For the 7 default RESTful actions, things haven't changed much. The only real difference is that you can now change step 2 (refer to list above), by passing a block to action.action.
create.action do
@post.my_custom_save_method
end
The action block's return value determines whether the success or failure callbacks (i.e. success.flash vs failure.wants) are triggered.
For custom actions, you'll now be able to use the same DSL you're used to for customizing default actions. For example, if you had a custom action called update_collection, you might put something like this in your routes:
map.connect '/posts', :controller => 'posts', :action => 'update_collection', :conditions => {:method => :put}
Based on that route, r_c will automatically be aware of your action, and create a basic skeleton for it, following the pattern of the list above. For a collection update method, you might want to customize your action like this:
update_collection do
before { @posts.each { |p| p.update_attributes params[:posts] } }
update_collection.action { @posts.save }
end
That's all you'd have to do. r_c would automatically load the objects (including any parent, respecting polymorphism), and render using its internal helpers.
Note: It is also possible to modify loading by setting a block for the build accessor, which corresponds to step 1.
Highly Experimental
This is highly experimental software. I'm not sure how much I love it, since it's a bit on the magical side for my tastes. However, it is kinda neat to have your controller be aware of which actions to create, based on what is routed to it. I have been having a bit of fun playing around with this.
So, please give it a shot, and let us know how you like it on the mailing list.
Get it from github (checkout the automatic_route_discovery branch). If you aren't using git, you can get a tarball here.
Feb 15, 2008
This is mainly a maintenance release.
- The helpers have been broken out in to four separate files internally, to help with managing the deep nesting branch.
- There have also been a few little refactorings in preparation for some new features to come shortly.
- The biggest thing to note for users is that there is no longer an edge_compatible branch. Since rails 1.2.6 generates the same style of named routes as 2.0.2 (edit_tag_photo_path instead of tag_edit_photo_path), there is no longer a need to continue two separate streams of development (yay)!.
- The generator has been updated to spit out the right filenames for templates (rhtml/haml vs html.erb/html.haml), and old-style migrations (t.column instead of t.string) for any users still stuck on 1.2.6, so the transition shouldn't be a problem.
Get It!
You can get the new version by exporting from svn:
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
Or, if you're using piston, you may need to switch to the new url if you were previously on edge compatible (this is untested, so it may be slightly wrong).
piston switch http://svn.jamesgolick.com/resource_controller/tags/stable
piston update
As always, everybody is encouraged to come join the discussion on the increasingly lively mailing list.
Jan 27, 2008
So, I'm sitting there on Friday evening working on a screencast introduction to attribute_fu, when Fabio Akita sends me an email to tell me he just created one for resource_controller! It was like he'd read my mind.
Fabio was nice enough to agree to let me put some title screens on his r_c screencast, but I couldn't seem to get it to export while still looking decent. So, here's the first episode of GiraffeCasts (for those of you who don't know, my company is called GiraffeSoft), and Fabio's awesome resource_controller introduction.
Episode 1: attribute_fu
Episode one is a quick walk through the basics of attribute_fu. Get it here.
As promised, here is the code from the screencast:
## _task.html.erb
<p class="task">
<b>Title:</b><br/>
<%= f.text_field :title %>
<%= f.remove_link('Remove') %>
</p>
## _form.html.erb
<div id="tasks">
<%= f.render_associated_form(@project.tasks, :new => 3) %>
</div>
<%= f.add_associated_link('Add Task', @project.tasks.build) %>
class Project < ActiveRecord::Base
has_many :tasks, :attributes => true
private
before_save :remove_blank_tasks
def remove_blank_tasks
tasks.delete tasks.select { |task| task.title.blank? }
end
end
To get attribute_fu:
$ piston import http://svn.jamesgolick.com/attribute_fu/tags/stable vendor/plugins/attribute_fu
Fabio's resource_controller Screencast
Fabio Akita gives an excellent tour of resource_controller, in screencast form. Get it here.
See Ya Next Time
That's all for today. Check back for more GiraffeCasts!
Nov 26, 2007
It's been a while since the last r_c release; I have been busy. I'm still busy, so this isn't a huge release, but these changes have been in SVN for a while, so I thought I'd share them.
There was a cool thread over at RefactorMyCode.com where we discussed some potential API improvements for r_c (it's still open - come share your ideas!). Here's what made it in to this release...
respond_to
respond_to now accepts symbols, and has a few extra names. All of these examples have the same effect...
create.response :html do |format|
format.js
end
create.respond_to :html, :js
create.responds_to do |format|
format.html
format.js
end
create.wants.html
create.wants.js
Callbacks Accept Symbols
I've always liked that the filters, and callbacks in rails accept the name of a method or a block. Now, all the callbacks in resource_controller accept them both, too!
create.before { @post.author = current_user }
create.before :set_user
private
def set_user
@post.author = current_user
end
Configuration-Style Syntax for model_name, route_name, and object_name
Now, rather than overriding a method to provide alternate model, object or route names, you can set them through a configuration-style interface (though, you can still override the methods if you prefer).
model_name :post_tag
route_name :tag
object_name :tag
Note: resource_name is gone as of this release. If you were overriding that in your controllers, you'll have to use a combination of the other helpers to get the same effect.
LOTS More Helper Methods Exposed
If you've had a problem with r_c helper methods not being exposed in your views, it should be solved now. Just about every possible r_c method is now available in your views!
Get It!
1.2.3+ Compatible
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
Edge/Rails 2.0 Compatible
svn export http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable vendor/plugins/resource_controller
If you're looking for older versions, try browsing http://svn.jamesgolick.com/resource_controller/tags.
For more info, see the resource_controller section of my blog.
Come join the discussion on the mailing list.
Nov 05, 2007
Now that I've gotten a few maintenance releases out the door, I'm starting to feel like r_c's feature set is pretty solid; I think most people's needs should be covered (still a few things left to include, but we're getting there). The next step in improving resource_controller is evolving the API. What better place to hold the discussion than Marc-André's refactormycode.com?
First Refactoring designing
In the comments of the last release post, Luigi Montanez brought up an issue that's been bugging me since I first released the plugin. Currently, some customizations (before/after callbacks, response blocks, etc) are made with a "DSL"-style API. Some customizations (like alternate model names), however, are made by overriding helper methods. It's not that I don't like overriding methods, but I find the API a bit inconsistent in that way.
Currently, providing an alternate model name looks like this...
class PostsController < ResourceController::Base
private
def model_name
'blog_post'
end
end
It would be really neat, though, if it was possible to set the model_name the same way you set the flash...
class PostsController < ResourceController::Base
model_name :blog_post
end
Please, come join the discussion at RmC, and put some of your ideas on the table for resource_controller's API.
Nov 01, 2007
Since last week, I've had some really great user feedback from the community. From that feedback, four new features made it in to this week's release. Here they are.
Support for Custom Route Names
Osh let me know that r_c didn't really support non-standard resource names. That is, it wasn't possible to have a controller whose name didn't match its model. Now, not only does r_c support non-standard resource names, but it supports every configuration of non-standard resources imaginable.
Osh's example was the simplest, and probably the most common. He has a resource with a name that doesnt't match the model. In that case, all you have to do is override model_name.
class TagsController < ResourceController::Base
private
def model_name
'photo_tag'
end
end
In that example, the variables, and form_builders available in your views would be named photo_tag(s). If you wanted to change that to match the name of your model, you'd override object_name.
class TagsController < ResourceController::Base
private
def model_name
'photo_tag'
end
def object_name
'photo_tag'
end
end
Your controller might have some non-standard name, too. If it does, just override route_name.
map.resources :tags, :controller => "photo_tags"
class PhotoTagsController < ResourceController::Base
private
def route_name
'tag'
end
end
All of those new helpers default to the value of the resource_name helper, which is derived from the name of the controller.
New Urligence Syntax
In order to support non-standard routes in resource_controller, Urligence has gained some new syntax. smart_url infers the name of a resource from an object's class name, so a non-standard route name was impossible. Now, if you provide a 2-element array parameter to smart_url, the first element (a symbol) is used as the resource name, and the second element is the object that is passed to the url helper. It looks like this...
smart_url([:tag, @photo_tag])
All of the old syntax is still, of course, valid, and can be mixed and matched with the new syntax.
hash_for, path, and url
On the topic of Urligence, Hsiu-Fan raised the issue that smart_url would only return paths. Not really an accurate method name, and not convenient if you want a URL, or a hash. Hsiu-Fan was also nice enough to send in a patch, which I refactored a bit, and now we have four methods.
smart_url
smart_path
hash_for_smart_url
hash_for_smart_path
Important: The smart_url method now outputs URLs, not paths. If you are depending on paths coming out of smart_url anywhere in your code, or tests, this may be a code breaking change.
r_c has also gained helpers for all of these methods...
[new_|edit_]object_url
[new_|edit_]object_path
hash_for_[new_|edit_]object_url
hash_for_[new_|edit_]object_path
collection_url
collection_path
hash_for_collection_url
hash_for_collection_path
New Instantiation Syntax
Another thing Osh brought up with me, during our back and forth, was his concern with r_c's inheritance syntax. Since there isn't any particular reason for that syntax other than the fact that I like it, I have added an alternative. Just say resource_controller, and you'll get the exact same effect as inheriting from ResourceController::Base.
class PhotosController < ApplicationController
resource_controller
end
Just make sure that you call the resource_controller method before you use any other r_c features.
Get It!
1.2.3+ Compatible
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
Edge/Rails 2.0 Compatible
svn export http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable vendor/plugins/resource_controller
If you're looking for older versions, try browsing http://svn.jamesgolick.com/resource_controller/tags.
For more info, see the resource_controller section of my blog.
Come join the discussion on the mailing list.
Oct 25, 2007
A week after I released resource_controller, there are a few issues that needed to be resolved.
Specifying Actions
Hampton pointed out the fact that I hadn't mentioned any way of specifying which actions a controller should respond to. You might want to have a controller that only responds to show, and index, for example. It was possible (and documented - see the RDocs), but somewhat broken. This release fixes that bug.
You can either provide a list of actions, or use :all, :except => syntax.
class PostsController < ResourceController::Base
actions :show, :index
actions :all, :except => :index
end
Generators
resource_controller comes with a scaffold_resource generator now. In the 1.2.3+ stream, it will override the built-in version. I figure - if you're using resource_controller, you probably won't have much need for the default one.
It's pretty clever, too. If you have Haml installed, it generates Haml. If you have Shoulda installed, it spits out functional tests that make use of Shoulda's wonderful should_be_restful macro (note: I'm not necessarily opposed to doing the same for RSpec, if there's demand - let me know). Otherwise, it spits out erb, and the same functional tests as the generator included with rails.
The syntax is exactly the same as the built-in generator.
script/generate scaffold_resource post title:string body:text
Get It
1.2.3+ Compatible
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
Edge/Rails 2.0 Compatible
svn export http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable vendor/plugins/resource_controller
If you're looking for older versions, try browsing http://svn.jamesgolick.com/resource_controller/tags.
For more info, see the release announcement.
Community
I also wanted to announce that I've created a google group for resource_controller.
Come join it, and discuss what can be done to make r_c even better!
Oct 19, 2007
If you're using rails, and you've kept up with what's happening in the community, and in the framework, you're probably writing RESTful apps. You may have noticed, like I did, that most of your controllers follow the same basic pattern - the one that the scaffold_resource (just scaffold in edge/2.0) generator spits out.
I wanted a great way to hide that pattern, and describe the unique features of my controllers through a more domain-specific API. Since I tend to write a lot of nested, and polymorphic resources, I also wanted to DRY up all of that code, and make generating urls a lot more intuitive. Finally, I wanted all of that code to be well-tested, so that I could count on hacking it up when I needed new features, without breaking things.
So, I created it, and here it is.
resource_controller
A basic, out of the generator resource just requires inheriting from ResourceController::Base.
class PostsController < ResourceController::Base
end
API
Before/after callbacks, responses, and flash messages are managed through an extremely flexible API. I tried my best, here, to make syntax succinct when your needs are succinct, and allow API calls to be organized in an intuitive way. What I came up with was a scoping system, where calls to the various API methods can be chained, or scoped with a block.
Take the create action, for example. You might want to add a before block, to assign the author attribute of your post model to the current user.
class PostsController < ResourceController::Base
create.before do
@post.author << current_user
end
end
As your application matures, you may want to add an RJS response to your create method, for some AJAXy goodness. Easy.
class PostsController < ResourceController::Base
create.before do
@post.author << current_user
response do |wants|
wants.html
wants.js
end
end
end
Actually, there's even a shortcut for
adding responses. You can omit the response block, if you just want to add responses to what's already provided by resource_controller (just HTML) or has been added elsewhere.
class PostsController < ResourceController::Base
create do
before do
@post.author << current_user
end
wants.js
end
end
Since I commonly use the same RJS template for several actions, I've found this short-form really handy, because I can use a one-liner to add the same response to several actions.
class PostsController < ResourceController::Base
[create, update].each { |action| action.wants.js {render :template => "post.rjs"} }
end
Oh yeah, and you can change the flash too.
class PostsController < ResourceController::Base
create.flash "Wow! RESTful controllers are so easy with resource_controller!"
end
For more API details, and examples, see the
RDocs.
Helpers
Helpers are used internally to manage objects, generate urls, and manage parent resource associations.
If you want to customize certain controller behaviour, like member-object, and collection fetching, overriding helper methods is all it takes.
Note:For certain resource_controller functionality to work properly, user-defined helpers must make use of the other r_c helpers. The following examples do not follow that convention for clarity purposes - see the docs for more details.
If you wanted, for example, to use a permalink for your post, you'd need to alter the way that posts are fetched. Just override the object method.
class PostsController < ResourceController::Base
private
def object
@object ||= Post.find_by_permalink(param[:id])
end
end
You'll probably also want to add pagination to your index method. In the same way we altered member object fetching, we can change collection fetching behavior.
class PostsController < ResourceController::Base
private
def collection
@collection ||= Post.find(:all, :page => {:size => 10, :current => params[:page]})
end
end
Details and examples in the
RDocs.
Namespaced Resources
...are handled automatically, and any namespaces are available, symbolized, in array form from the namespaces helper method.
Nested Resources
Again, handled automatically. This can be a real pain, and it's a
lot easier with r_c. With an ActiveRecord-like syntax, just say belongs_to :model, and resource_controller takes care of the associations for you.
class CommentsController < ResourceController::Base
belongs_to :post
end
Polymorphic Resources
This is a concept that can be found in a lot of my apps. Prior to resource_controller, it was a real pain on various levels. I solved some of my problems with
urligence, and took things the rest of the way with resource_controller. It really does pretty much everything for you.
Just use the belongs_to syntax in your controller, and r_c infers whichever association (if any) is present when an action is called. The arguments passed to belongs_to are single possible parents; there is no support for deeply nested resources (although, I'm not necessarily opposed to adding it, if there is demandwe).
class CommentsController < ResourceController::Base
belongs_to :post, :product
end
In the above example, the controller will automatically infer the presence of either a parent Post, or Product, and scope all the comments to that parent. The controller will also respond without a parent if you have that in your routes.
Thanks to urligence, generating urls in your polymorphic controller's views is
really easy. The object_url, and collection_url helpers will maintain your parent resource's scope automatically.
object_url
object_url(comment)
edit_object_url
collection_url
object_url
object_url(comment)
edit_object_url
collection_url
object_url
object_url(comment)
edit_object_url
collection_url
More in the
RDocs.
Getting it
resource_controller is available under the MIT License.
It is currently available in two streams:
1.2.3+ Compatible
Install it:
svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller
SVN (stable): http://svn.jamesgolick.com/resource_controller/tags/stable
SVN (ongoing): http://svn.jamesgolick.com/resource_controller/trunk
Note: If you want to run the tests, cd in to the test directory, and type rake test.
Edge/Rails 2.0 Compatible
Install it:
svn export http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable vendor/plugins/resource_controller
SVN (stable): http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable
SVN (ongoing): http://svn.jamesgolick.com/resource_controller/branches/edge_compatible
Note: If you want to run the tests in the edge-compatible version, cd in to the test directory, and type rake rails:freeze:edge. I didn't want people to have to download all of edge rails just to get the plugin.
Also, check out the rdoc
Feedback
Drop me a line and let me know what you think. I'd love to hear your suggestions for API or implementation improvements, or anything else!