Singular Resource

Extracted from decent exposure, attempts to leave the useful parts, and just use helper_method to expose your view models.

DOES

Allow you to find or initialize a simple resource, removing the boilerplate from CRUD actions.

DOES NOT

Expose the model in any way, scope the query to a collection method if defined, or deal with collections.

Use

It provides a private method that performs a query for the document when invoked whenever id is defined. When there is no id parameter, like in new and create, it returns an initialized model.

   # app/controllers/person_controller.rb
   class PersonController < ApplicationController
      singular_resource :person

      def destroy
         person.destroy
         redirect_to action: :index
      end
   end

Strategies

Like decent_exposure, it's configurable, and provides different strategies. By default, it uses StrongParametersStrategy, which only assigns the attributes if a method name is provided via the attributes option.

Options

          optional: "Return nil if the document does not exist when passed a truthy value",

             model: "Class or name of the model class",

  finder_parameter: "Name of the parameter that has the document's id",

        attributes: "Name of the attributes method name if using strong parameters",

         param_key: "Name of the parameter that has the document's attributes"

Comparison

What singular_resource proposes is that you go from this:

class Controller
  def new
    @person = Person.new(params[:person])
  end

  def create
    @person = Person.new(params[:person])
    if @person.save
      redirect_to(@person)
    else
      render :new
    end
  end

  def edit
    @person = Person.find(params[:id])
  end

  def update
    @person = Person.find(params[:id])
    if @person.update_attributes(params[:person])
      redirect_to(@person)
    else
      render :edit
    end
  end
end

To something like this:

class Controller
  expose(:person)

  def create
    if person.save
      redirect_to(person)
    else
      render :new
    end
  end

  def update
    if person.save
      redirect_to(person)
    else
      render :edit
    end
  end
end

With draper

If you use decorators, you can go from something like this:

class Controller
  def new
    @person = Person.new(params[:person]).decorate
  end

  def create
    @person = Person.new(params[:person])
    if @person.save
      redirect_to(@person)
    else
      @person = @person.decorate
      render :new
    end
  end

  def edit
    @person = Person.find(params[:id]).decorate
  end

  def update
    @person = Person.find(params[:id])
    if @person.update_attributes(params[:person])
      redirect_to(@person)
    else
      @person = @person.decorate
      render :edit
    end
  end
end

To something like this:

class Controller
  before_filter :decorate_person

  singular_resource(:person)

  def create
    if person.save
      redirect_to(person)
    else
      render :new
    end
  end

  def update
    if person.save
      redirect_to(person)
    else
      render :edit
    end
  end

  private
    def decorate_person
      @person = person.decorate
    end
end

If you think that the before_filter is nasty or don't like ivars in your views, so do I! Check the presenter_rails gem

Special Thanks

Singular Resource is a subset of decent_exposure.