module Cell module Rendering extend ActiveSupport::Concern # Invoke the state method for +state+ which usually renders something nice. def render_state(state, *args) process(state, *args) end # Renders the view for the current state and returns the markup. # Don't forget to return the markup itself from the state method. # # === Options # +:view+:: Specifies the name of the view file to render. Defaults to the current state name. # +:layout+:: Renders the state wrapped in the layout. Layouts reside in app/cells/layouts. # +:locals+:: Makes the named parameters available as variables in the view. # +:text+:: Just renders plain text. # +:inline+:: Renders an inline template as state view. See ActionView::Base#render for details. # +:file+:: Specifies the name of the file template to render. # +:nothing+:: Doesn't invoke the rendering process. # +:state+:: Instantly invokes another rendering cycle for the passed state and returns. You may pass arbitrary state-args to the called state. # +:format+:: Sets a different template format, e.g. +:json+. Use this option with caution as it currently modifies the global format variable. This might lead to unexpected subsequent render behaviour due to a design flaw in Rails. # # Example: # class MusicianCell < ::Cell::Base # def sing # # ... laalaa # render # end # # renders the view musician/sing.html. # # def sing # # ... laalaa # render :view => :shout, :layout => 'metal' # end # # renders musician/shout.html and wrap it in app/cells/layouts/metal.html.erb. # # === #render is explicit! # You can also alter the markup from #render. Just remember to return it. # # def sing # render + render + render # end # # will render three concated views. # # === Partials? # # In Cells we abandoned the term 'partial' in favor of plain 'views' - we don't need to distinguish # between both terms. A cell view is both, a view and a kind of partial as it represents only a fragment # of the page. # # Just use :view and enjoy. # # === Using states instead of helpers # # Sometimes it's useful to not only render a view but also invoke the associated state. This is # especially helpful when replacing helpers. Do that with render :state. # # def show_cheap_item(item) # render if item.price <= 1 # end # # A view could use this state in place of an odd helper. # # - @items.each do |item| # = render({:state => :show_cheap_item}, item) # # This calls the state method which in turn will render its view - if the item isn't too expensive. def render(*args) render_view_for(self.action_name, *args) end private # Renders the view belonging to the given state. Will raise ActionView::MissingTemplate # if it can't find a view. def render_view_for(state, *args) opts = args.first.is_a?(::Hash) ? args.shift : {} return "" if opts[:nothing] if opts[:state] opts[:text] = render_state(opts.delete(:state), *args) elsif (opts.keys & [:text, :inline, :file]).blank? process_opts_for(opts, state) end render_to_string(opts).html_safe # ActionView::Template::Text doesn't do that for us. end module ClassMethods # Main entry point for #render_cell. def render_cell_for(name, state, *args) cell = create_cell_for(name, *args) yield cell if block_given? render_cell_state(cell, state, *args) end private def render_cell_state(cell, state, *args) cell.render_state(state, *args) end end end end