I am using Rack middle ware to intercept all requests to my rails app. I am checking for a particular parameter in the query string. If the request has the parameter, I need to extract its value and put it in a database to be processed later. Otherwise I let the normal course of action to continue. Any ideas how to implement it?
P.S : I have done the following already.
1) I can extract the value of my desired parameter through Rack and send it along with the response (For testing purposes only)
2) I have tried created a custom controller and call it from the rack, but I am hitting upon undefined method error everytime.
Any help will be appreciated.
Related
Overview
I want to implement the Google OAuth2 server side (hybrid) with the Omniauth Google OAuth2 Gem (0.2.6). However, the code parameter I send to my app does not get added to the request.params hash. Thus, OmniAuth throws an error, as it can't find the code.
Details
After retrieving the auth code from Google I send it to the server (by AJAX):
// Send the code to the server
$.ajax({
type: 'POST',
url: '/auth/google_oauth2/callback',
contentType: 'application/json',
success: function(result) {
// Handle or verify the server response.
},
processData: false,
data: JSON.stringify(password_result)
});
This throws the error:
"error" : "invalid_request",
"error_description" : "Missing required parameter: code"
After going through the stack, I figured out the following:
As long as I have 'application/json' set as content Type, Rack parses the params correctly and the env object contains the parsed parameters:
"action_dispatch.request.request_parameters"=>{"code"=>"<sent_in_code>"}
However, the request.params hash remains empty. Since OmniAuth checks for request.params['code'], this is the source of the error.
request.POST is empty, which from looking at the source code of Rack is the underlying cause for the empty request.params hash.
When sending the code in standard format as data:"code="+authResult['code'], the parameter is available in the request.params hash. (I get a strange undefined route error then, but this is a different issue.)
Questions
Now, even though I can avoid the issue by not using JSON, I'm still very intereted in the answers to the following questions:
Why is the code parameter not available in request.POST/request.params, even though it gets parsed correctly?
Is there a way to fix this, so I can still send the auth code in JSON to my app?
I've spent two afternoons trying to get the answers myself, but haven't really gotten to a good conclusion so far.
omniauth-google-oauth2 tries to get the auth code from the Rack::Request.params hash. However, Rack apparently does not have JSON parsing built-in. Params calls POST which then calls form_data? which only looks for application/x-www-form-urlencoded or multipart/form-data. It then also tries parseable_data?, which does not parse JSON either. Seems like Rack does not support JSON out of the box, also look at this answer.
The "action_dispatch.request.request_parameters"=>{"code"=>"<sent_in_code>"} hash works because this is done by rails ActionDispatch::Request, which subclasses Rack::Request. However because The omniauth gem is included in your app as a Rack middleware, it does not know of the ActionDispatch request object.
The question remains why this example uses JSON.
Possible solutions:
money-Patch JSON Support into Rack - not recommended
just use application/x-www-form-urlencoded - recommended
I've googled for the past hour still couldn't find a command that tells Rails that it should not cache anything on that controller.
Not even a single fragment, every query should be performed ...
Any suggestions?
Notes:
Rails: 4.0.9
caching: dalli
Reason:
I use heavy Javascript within that controller - when a user does an action Javascript fetches the newest result from a JSON feed.
example:
root_url/events/all-events.json therefore it's important that Rails does not cache.
You can do it by adding a parameter to the url
just use :
root_url/events/all-events.json?t=#{Time.now.to_i}
when you fetch it, and it will be fetched uncached
also, you can try try the action controller method expires_now
add it to a :before_filter
I have a ruby on rails api where I want to sign my request data by appending a hashed version of all passed in parameters to the request and rebuild this one at the server side as well to validate the integrity of the requests.
When I simply use the params method in the controller I have different parameters (e.g. for an update-method which is specified by this:
put 'login' => 'login#update'
I get as parameters on the server:
{"timestamp"=>"1399562324118", "secured"=>"xxx",
"login"=>{"timestamp"=>"1399562324118", "secured"=>"xxx"}}
although I only send the request from the client with
{"timestamp"=>"1399562324118", "secured"=>"xxx"}
Does any one have an idea how to get rid of this "login" parameter in the params list in a generic way? I do not want to exclude this for every single request of my api.
Thanks a lot!
Per the Rails Edge guide on ActionController:
"If you've turned on config.wrap_parameters in your initializer or calling wrap_parameters in your controller, you can safely omit the root element in the JSON parameter"
See http://guides.rubyonrails.org/action_controller_overview.html#json-parameters
I want to use ExtDirect for a 3rd party extjs user interface in Rails 3. So I have started to update the active-direct gem to work with Rails 3. Here is the updated version: https://github.com/stonegao/active-direct
At the moment my modified active direct plugin/gem works with models. I'm able to do this in JavaScript:
App.namespace.Project.all({params},callback_function);
That's great.
Now I want to use some special Rails 3 controllers (that act like a service).
In my Extdirect JS is this:
App.mynamespace.MyProject_Controller_V1_workspaceController.getStatus
This response also comes to my extjs router. No I want call this controller action and get the response.
I can't use #app.call(env) with a changed request_uri because I have no match in routes.rb
Is it possible to call this controller action
Specification of extdirect: http://tinyurl.com/4y3nc44
Thanks skeller1
yes, it is!
just do something like this:
status,headers,response=ProjectsController.action("index").call(#env)
so you can call the index method of the ProjectsController.
beware: ExtDirect accepts all types in the HTTP_ACCEPT http header field.
so you can do a
#env['HTTP_ACCEPT'] = "application/json"
before your request to an action to set your wanted response type.
I was looking at the rails 3 architecture in order to understand the process of dispatching a request . The whole process is quite simple. Application is a rack application which finally delegates its call message to the call method of ActionDispatch::Routing::RouteSet which dispatches appropriate action of necessary controller. It takes controller and action names from the hash stored in rack env by the key "action_dispatch.request.path_parameters".
So the question is: Who sets this hash? Who parses request uri and determines action and controller names?
I was not able to find this code. I see that during route configuration ActionDispatch::Routing::Mapper object is used to construct information about defined routes and stores it in ActionDispatch::Routing::RouteSet. But how this information is used during the request to find appropriate action and controller. Is rack also somehow involved here?
"action_dispatch.request.path_parameters" is stored as the constant ActionDispatch::Routing::RouteSet::PARAMETERS_KEY (actionpack/lib/action_dispatch/routing/route_set.rb)
PARAMETERS_KEY is used later on in that same file and passed into the constructer for ::Rack::Mount::RouteSet
Going to ::Rack::Mount::RouteSet source here: https://github.com/josh/rack-mount/blob/master/lib/rack/mount/route_set.rb#L22 you can see that attribute name is stored.
Same file, down in the call(env) method which is of course the Rack interface that will be called into, we see this line ( https://github.com/josh/rack-mount/blob/master/lib/rack/mount/route_set.rb#L147 ) where your env["action_dispatch.request.path_parameters"] attribute is actually set, and eventually returned back into the code you were investigating.
Hope this helps!