views:

27

answers:

1

Hello,

I'm wrestling with something that should be very simple - specify a sidebar at the controller level. With layouts you can do this:

layout 'admin'

so I'd like to do the same for a sidebar, with something like this:

sidebar 'search'

I know I could specify the sidebar markup with content_for in the views, but I'd rather specify the sidebar at the controller level and not repeat code in (and clutter up) my views. I'd also like to be able to share sidebars between controllers.

At the moment I've got this in an initializer (a plugin seems like overkill for something so simple):

module Sidebar
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def sidebar(partial)
      # neither of these two work...
      @sidebar = partial
      instance_variable_set('@sidebar', partial)
    end
  end
end

ActionController::Base.send(:include, Sidebar)

and then in my layout I'm trying

<%= render "shared/#{@sidebar}" %>

but to no avail...

Does anyone know what I'm doing wrong, or if indeed I'm going about this the right way at all? Any help is greatly appreciated!

+2  A: 

This is a scope issue. The view requires an instance variable but your sidebar method works in the class scope.

module Sidebar
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def sidebar(partial)
      before_filter do |controller|
        controller.instance_eval { @sidebar = partial }
      end
    end
  end
end

ActionController::Base.send(:include, Sidebar)

If all your controllers include a sidebar, then you can consider to define an instance variable in your application controller.

class ApplicationController < ActionController::Base

  attr_accessor :sidebar

end

module Sidebar
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def sidebar(partial)
      before_filter do |controller|
        controller.sidebar = partial
      end
    end
  end
end

ActionController::Base.send(:include, Sidebar)

Also, if you don't have other methods, you can simplify your mixin even further.

class ApplicationController < ActionController::Base
  attr_accessor :sidebar
end

module Sidebar
  def sidebar(partial)
    before_filter do |controller|
      controller.sidebar = partial
    end
  end
end

ActionController::Base.extend(Sidebar)

Personally I don't like too much this approach. I prefer to define the content of a sidebar in the view file and fallback to a standard value in case no custom value is set.

Simone Carletti
Hi Simone,thanks for your answer, that makes sense. I've been thinking about it however and I've come to the conclusion that although it might mean specifying the same sidebar partial in all the views for a controller, it's better to define the sidebar in the view and fallback to a default as you say.CheersDave
fishwebby