More on RestController and some updates 2

Posted by Tim Connor Fri, 20 Apr 2007 18:58:00 GMT

I’ve fleshed out RestController, through some more usage. Combined with moving associated object creation into the model, it now really DRYs out my code, by being a little more flexible.

On any overridden action you can call super, passing in an option options hash. The current options are :template, which works for the editing template for errors on update and create and :find_options, for sorting the index view, for instance. As well, the instance variables (@page_title and @your_model_name) are set with ||=, so you can do custom init and then call super.

Well a picture is worth a thousand words, so, here are the public methods, using all of these techniques, from my most complicated controller on a project using it:

  def index(options = {})
    super ({:find_options => {:order => 'date DESC'}}.merge(options))
  end

  def public_index
    @page_title = 'Sun Valley Fishing Report'
    @body_class = 'archive'
    index :template => 'public_index'
  end

  def current
    @report = Report.current
    @page_title = 'Latest Sun Valley Fishing Report'
    public_show
  end

  def public_show
    @report ||= Report.find_by_date(params[:date])
    @page_title ||= 'Sun Valley Fishing Report'
    render :text => 'No report found', :layout => 'public' and return unless @report
    show :template => 'public_show'
  end

  def new
    @report = Report.new()
    Location.find(:all).each { |location| @report.conditions.build(:location => location) }
    super
  end

  def edit
    @report = Report.find(params[:id])
    Location.find(:all).each { |location|
      @report.conditions.build(:location => location) unless @report.locations.include?(location)
    }
    super
  end
Most of the other controllers ones are a couple of lines, maybe over-riding one action. For instance, here is my UserController, and even this might be simplified when I add in an error condition on edit and show (and/or an passed in error handling block):

class UsersController < REST::RestController
  def edit
    @user = User.find_by_id(params[:id])
    unless @user
      flash[:notice] = @@messages[:editing_invalid_id]
      redirect_to users_path and return
    end
    super
  end
end

UPDATE: Same day – I updated again, and now I can empty out that user controller, because the edit and show actions have basic checks for not found.

Dynamic-Scaffold-Resource is dead, long live RestController 4

Posted by Tim Connor Tue, 03 Apr 2007 18:39:00 GMT

I got tired of the complexities of my plug-in solution to DRYing up the shared code in all my Restful controllers, and scaffolding gets no love from core. But after a little while I got almost as tired of having the same 7 methods repeated throughout my code base. Thus a new simpler project is born: RestContoller.

Instead of scaffolding your views (which the core team is right about – those should diverge widely to fit the UI needs) or adding tests for you, it just gives you a main rest controller to inherit from that has the 7 basic actions (index, show, new, edit, create, update, and destroy). I was also able to simply further and drop the giant block eval, by looking over Jake Howerto’s CRUDController and borrowing a technique or two (such as the use of instance_variable_set). This should make the code easier to follow, customize, and also more performant.

You can just do a vanilla checkout from Google Code, and then inherit from that.

svn checkout http://restcontroller.googlecode.com/svn/trunk/ app/controllers/rest
class YourModelController < REST::RestController
but with this new approach it’s much more natural to customize per project. You can just go ahead and grab the file, save a local copy, check it into your own source control, and do with it as you will. For instance, if all of your resources have a public facing front, but the rest should be restricted, just add something like this (as well as the appropriate function in your application.rb)
before_filter :require_login, :except =>[:show, :index]