Skip to content

Instantly share code, notes, and snippets.

@catmando catmando/controller_op.rb
Last active Jun 22, 2017

Embed
What would you like to do?
hyper operation Controller Operation experimental patch
# app/hyperloop/operations/controller_op.rb
# make sure to also require 'operations/controller_op'
# at the *END* of config/initializers/hyperloop.rb
module Hyperloop
# monkey patch HyperloopController to pass controller instance from controller method to ServerOp
Engine.routes.append do
class HyperloopController < ::ApplicationController
def execute_remote
parsed_params = JSON.parse(params[:json]).symbolize_keys
render ServerOp.run_from_client(
:acting_user,
self, # this gets added
parsed_params[:operation],
parsed_params[:params].merge(acting_user: acting_user)
)
end
def execute_remote_api
params.require(:params).permit!
parsed_params = params[:params].to_h.symbolize_keys
raise AccessViolation unless parsed_params[:authorization]
# likewise add self here as second param
render ServerOp.run_from_client(:authorization, self, params[:operation], parsed_params)
end
end
end unless RUBY_ENGINE == 'opal'
# monkey patch run_from_client so it accepts controller
class ServerOp < Operation
def self.run_from_client(security_param, controller, operation, params)
operation.constantize.class_eval do
# if the params expect a controller then merge it in
# and if we are passing in a controller then we can ignore the security param
if _Railway.params_wrapper.method_defined?(:controller)
params[:controller] = controller
# but if we are not passing a controller, then we must have th security param defined
elsif !_Railway.params_wrapper.method_defined?(security_param)
raise AccessViolation
end
run(params)
.then { |r| return { json: { response: serialize_response(r) } } }
.fail { |e| return { json: { error: e}, status: 500 } }
end
rescue Exception => e
{ json: {error: e}, status: 500 }
end
end unless RUBY_ENGINE == 'opal'
# at this point you can add a controller param to a ServerOp and you will be able to use it
# but to make things nice we will define a subclass that already takes the controller
# and then make the Operation act like a Controller delegate
class ControllerOp < ServerOp; end
class ControllerOp < ServerOp
param :controller
alias pre_controller_op_method_missing method_missing
def method_missing(name, *args, &block)
if params.controller.respond_to? name
params.controller.send(name, *args, &block)
else
pre_controller_op_method_missing(name, *args, &block)
end
end
end unless RUBY_ENGINE == 'opal'
end
# example Operation using ControllerOp subclass
require 'operations/controller_op'
class GetSessionId < Hyperloop::ControllerOp
step { session.delete 'hyperloop-dummy-init' unless session.id }
step { session.id }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.