## # Merb::ExtJS::Direct::RemotingProvider # @mixin # This is a mixin which provides support Merb support for ExtJS's Ext.Direct mechanism in Ext3.x #

Defining and registering the Ext.Direct api

# # # # #

Configuring your Merb Ext.Direct controller

# # class MyController # include Merb::Ext::Direct::RemotingProvider # <-- include this mixin. # end # # #

By including RemotingProvider mixin, your controller will have added to it a single action called "rpc" # with which you can send all you Ext.Direct actions to. Take note of the url specified in the first step.

# #

Merb-parts

# Ext.Direct is implemented in Merb by taking advantage of "Parts". The nice thing about parts is that they # have both a view (for rendering you Ext controls and api along with a controller for executing your api actions. # # # # The Merb RemotingProvider mixin takes advantage of the merb-parts gem. # # Ext.Direct router # @usage include Ext::Direct::RemotingProvider # @author Chris Scott # @TODO before_actions # module Merb::ExtJS::Direct module RemotingProvider # standard ruby method called when some class does: # include Ext::Direct::RemotingProvider def self.included(base) # must explicity specify controller-actions to make callable. security-wise, this is a *good* thing. # just one action is added. base.show_action(:rpc) end ## # rpc # remote procedure call handler for Ext.direct requests. # def rpc if !request.ajax? && !params["extAction"] return "Ext::Direct::RemotingProvider#rpc -- This method is an ajax-handler only" end is_form = false is_upload = false if params["extAction"] && params["extMethod"] # create fake response here. is_form = true is_upload = params.delete("extUpload") == 'true' request = { "xcontroller" => params.delete("extAction"), "xaction" => params.delete("extMethod"), "type" => "rpc", "id" => params.delete("id"), "tid" => params.delete("extTID"), "format" => params.delete("format"), "data" => params } params.delete('controller') params.delete('action') res = "" return res elsif (params[:inflated_object]) # multiple requests found. I'm not sure how this "inflated_object" mechanism works. This is Merb magic? # controllers always return a string, so each response has already been json-encoded. # since we're dealing with multiple requests here, we have to manually string-concat-wrap the retured # string-of-json. # return "[" + params[:inflated_object].collect {|req| handle_request(req)}.join(',') + "]" else ## # just a single request found # return handle_request(params) end end ## # protected # ## ## # handle_request # # @throws XException when anything goes wrong to gracefully handle on client. # @see Merb::Controller#part method, google: "merb parts". A Merb "part" is a kind of sub-controller # with its onwn view capabilites but cannot be directly routed-to. Using part() method here is similar # to using Ext.getCmp(id), eg: part(req.controller => req.action) ~ Ext.getCmp(controller).doSomething(action); # However, unlike Ext.getCmp(), part(controller => action) returns a string to be added to the render stream # and not a component instance, just as all merb render actions. # def handle_request(req) req = XRequest.new(req) begin # here be your Ext.direct.Transaction as a ruby Hash. # turn it into an offical ruby XRequest instance. # constantize the "controller" (ie: String "ArtistPart" becomes Class ArtistPart) and send "action" to it. # NOTE: Extlib has nothing to do with ExtJS -- just a coincidence. Extlib is a Merb gem. return part(Extlib::Inflection.constantize(req.controller) => req.action, :xrequest => req) rescue XException => e # caught an XException...return an Ext.Direct-friendly XExceptionResponse return XExceptionResponse.new(req, e).to_json rescue StandardError => e # might be an invalid controller and/or action if we got here. # we can be more specific here and trap on NameError if we wish, intead of base StandardError return XExceptionResponse.new(req, e).to_json end end end end