= Resourcelogic *Beta warning: right now this plugin is in what I like to call a "semi-beta". The only thing left to do is write documentation and add in the tests. I have already thoroughly tested this in a separate application, and am in the process of moving over the tests without having to pull over the entire rails application.* The purpose of Resourcelogic is to support a development style I created called "Contextual Development" (see contextual development below). This is an idea I've had for a while and finally decided to give it a try on one of my projects. This library spawned out of the {resource_controller plugin}(http://github.com/giraffesoft/resource_controller) by James Gollick, which is an excellent plugin. I eventually made so many changes to it that it made more sense to rewrite my own. == Helpful links * Documentation: http://resourcelogic.rubyforge.org == Contextual Development The idea behind contextual development is simple: *an API should be a be a byproduct of good design*. Meaning you should never have to explicitly build an API, it should be an "accident". Your interface should not dictate the structure of your controllers. Instead, your controllers should represent a collection of resources that your interface can use. The problem is that rails does so much magic, and makes so many assumptions, that sometimes it distorts the basics behind the MVC pattern. This becomes very clear when you try build an interface with {Flex}[http://www.adobe.com/products/flex/]. What this forces you to do is separate your interface from your application. A flex interface communicates with your application via XML. So when you finish an app with a Flex interface you all of a sudden have a "production ready" API as well. Which feels really good. A proper API is the foundation for growing your application. Once this is done the sky is the limit. That being said, why can't we accomplish the same thing with an HTML interface? For one, an HTML interface isn't as cleanly decoupled from the controllers as a Flex interface. For two, rails doesn't give us all of the tools to properly accomplish this. Instead, people create work-arounds by namespacing controllers to represent context and scope. Instead, why not have a single controller that is *context aware*. Hence the name *"Contextual Development"*. This is great because now you have a single controller that *every* request for the resource must pass through. In the same manner that all database activity passes through ORM models. You can feel confident adding controller specific logic to that resource without having to worry about duplicating it across multiple controllers. Ex: storing the user's IP address with a record. If it is any consolation, I am speaking from experience. I recently finished a very complex project using this method and I can say, without a doubt, it's the cleanest application I've built to date. == Install and use === 1. Install the gem Install the gem / plugin (recommended) $ sudo gem install resourcelogic Now add the gem dependency in your config: # config/environment.rb config.gem "resourcelogic" Or you install this as a plugin (for older versions of rails) script/plugin install git://github.com/binarylogic/resourcelogic.git === 2. Create your ResourceController script/generate controller resource Your ResourceController should look something like: class ResourceController < ApplicationController acts_as_resource end Now all of your controllers that are "resources" can extend this controller. Why do this? So you can set your default behavior for resources in one spot. This idea what brought over from the resource_controller plugin. The syntax resource_controller came up with is pretty cool: class ResourceController < ApplicationController acts_as_resource create.flash { # code to evaluate to create the flash message for a successful create } create.before { # code you want to execute before the create action } create.wants.js { # code you want to execute in the wants.js for a successful create } create.failure.flash { # code to evaluate to create the flash message for an unsuccessful create } create.failure.js { # code you want to execute in the wants.js for an unsuccessful create } # etc...See Resourcelogic::ActionOptions and Resourcelogic::FailableActionOptions for more details end All of these are overrideable, meaning your subclasses can change behavior in a granular manner, and preserve the defaults where necessary. === 3. Make sure you don't namespace your controllers Instead of namespacing your controllers, give them context. For example, let's say you you have /commments and /admin/comments. This controller has 2 contexts: root and admin. So your routes should look something like: map.with_options(:path_prefix => "admin", :name_prefix => "admin_") do |admin| admin.resource :comments end map.resources :comments Then in your controller use the context method to make adjustments: class CommentsController < ResourceController layout :layout_by_context private def layout_by_context case context when :admin "admin" else "application" end end end You also have the same context method in your views. Lastly, if you feel your views are getting cluttered you can use the contextual_views option (See Resourcelogic::Context::Config for more info). This will change your default view path to a context subfolder. Ex: /comments /admin /root any other contexts.. See the Feature Highlights section below for more options, and the documentation for a complete list. == Feature highlights I don't want to repeat what is already in the documentation, but there are a lot of really nice configuration and utility methods. Here are just a few: *Class level methods* belongs_to :relationship_name # will check to see if the resource is being scoped by a parent and give you some nifty methods for this (see below). You can call this multiple times. Just like ActiveRecord. contextual_views true # will split up your views into subfolders: comments/context1, comments/context2, and will change your default view path to the respecive folder *Instance level methods* context # the name of the context you are in object # current object collection # current collection object_path # /comments/:id new_object_path # /comments/new collection_path # /comments parent # current parent object parent_path # /parent_name/:parent_id parent_collection_path # /parent_name new_parent_path # /parent_name/new sibling_path(sibling) # /sibling_name/:id new_sibling_path(:sibling_name) # /sibling_name/new sibling_collection_path(:sibling_name) # /sibling_name child_path(child) # /sibling_name/:id new_child_path(:child_name) # /sibling_name/new child_collection_path(:child_name) # /sibling_name All of the above can end with _url instead of _path. See docs for a complete list of available methods. Copyright (c) 2008 {Ben Johnson of Binary Logic}(http://www.binarylogic.com), released under the MIT license