feat(controller): add controller base with before and after actions
This commit is contained in:
1 parent
6082190dac
commit
86e37e630f
1 file changed
+120
@@ -0,0 +1,120 @@
|
||||
module Prism
|
||||
class Controller
|
||||
include Renderable
|
||||
|
||||
class << self
|
||||
def before_actions
|
||||
@before_actions ||= []
|
||||
end
|
||||
|
||||
def after_actions
|
||||
@after_actions ||= []
|
||||
end
|
||||
|
||||
def before_action(*names, only: nil, except: nil, &block)
|
||||
register_filter(before_actions, names, only, except, block)
|
||||
end
|
||||
|
||||
def after_action(*names, only: nil, except: nil, &block)
|
||||
register_filter(after_actions, names, only, except, block)
|
||||
end
|
||||
|
||||
def layout(name = :missing)
|
||||
@layout = name unless name == :missing
|
||||
defined?(@layout) ? @layout : superclass_layout
|
||||
end
|
||||
|
||||
def views_root(path = nil)
|
||||
@views_root = path if path
|
||||
@views_root || superclass_views_root || 'app/views'
|
||||
end
|
||||
|
||||
def controller_path
|
||||
Inflector.underscore(name.to_s.split('::').last.sub(/Controller\z/, ''))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def superclass_layout
|
||||
superclass.respond_to?(:layout) ? superclass.layout : nil
|
||||
end
|
||||
|
||||
def superclass_views_root
|
||||
superclass.respond_to?(:views_root) ? superclass.views_root : nil
|
||||
end
|
||||
|
||||
def register_filter(store, names, only, except, block)
|
||||
names.each { |name| store << { name: name, block: nil, only: only, except: except } }
|
||||
store << { name: nil, block: block, only: only, except: except } if block
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :request, :response, :env, :action_name
|
||||
|
||||
def initialize(env, action_name, path_params = {})
|
||||
@env = env
|
||||
@request = Request.new(env)
|
||||
@request.path_params = path_params
|
||||
@response = Response.new
|
||||
@action_name = action_name.to_s
|
||||
end
|
||||
|
||||
def process
|
||||
catch(:halt) do
|
||||
run_before_actions
|
||||
finalize_body(send(@action_name))
|
||||
end
|
||||
catch(:halt) { run_after_actions }
|
||||
finalize_flash
|
||||
@response.finish
|
||||
end
|
||||
|
||||
def render(view = action_name, layout: self.class.layout, locals: {})
|
||||
content = view_resolver.render("#{self.class.controller_path}/#{view}", locals: locals, layout: layout)
|
||||
html(content)
|
||||
end
|
||||
|
||||
def partial(name, locals: {})
|
||||
view_resolver.render_partial(partial_path(name), locals: locals)
|
||||
end
|
||||
|
||||
def render_each(name, collection, locals: {}, as: nil)
|
||||
view_resolver.render_collection(partial_path(name), collection, locals: locals, as: as)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def finalize_body(result)
|
||||
return unless @response.body.empty?
|
||||
@response.body = [result.to_s] if result.is_a?(String)
|
||||
end
|
||||
|
||||
def partial_path(name)
|
||||
name.to_s.include?('/') ? name.to_s : "#{self.class.controller_path}/#{name}"
|
||||
end
|
||||
|
||||
def view_resolver
|
||||
@view_resolver ||= View.new(self.class.views_root)
|
||||
end
|
||||
|
||||
def run_before_actions
|
||||
self.class.before_actions.each { |filter| run_filter(filter) }
|
||||
end
|
||||
|
||||
def run_after_actions
|
||||
self.class.after_actions.each { |filter| run_filter(filter) }
|
||||
end
|
||||
|
||||
def run_filter(filter)
|
||||
return unless applies?(filter)
|
||||
filter[:block] ? instance_exec(&filter[:block]) : send(filter[:name])
|
||||
end
|
||||
|
||||
def applies?(filter)
|
||||
action = @action_name.to_sym
|
||||
return filter[:only].include?(action) if filter[:only]
|
||||
return !filter[:except].include?(action) if filter[:except]
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user