Same Rails 4 routes for GET and POST requests - ruby

In Rails 3 Match used to point to an action for both "GET" and "POST" and other type of requests.
match "user/account" => user#account
Now this will point to account action of user's controller for both GET and POST requests.
As in Rails 4 "match" has been deprecated, can we create same route for GET and POST in Rails 4?

From the match documentation, you can use match as long as you have via:
match "user/account" => "user#account", as: :user_account, via: [:get, :post]
Edit: Added a as: parameter so that it will be accessible via a url helper. user_account_path or user_account_url in this case.

On routes, the match method will no longer act as a catch-all option. You should now specify which HTTP verb to respond to with the option :via
Rails 3.2
match "/users/:id" => "users#show"
Rails 4.0
match "/users/:id" => "users#show", via: :get
or specify multiple verbs
match "/users" => "users#index", via: [:get, :post]
Another option for better Rails 3.2 compatibility is to just specify your actions with explicit get, post, or any other HTTP verb. With this option, you still get your code running today and future proof it for the upgrade.
Rails 3.2 and 4.0 compatible
get "/users/:id" => "users#show"
multiple verbs
get "/users" => "users#index"
post "/users" => "users#index"

Related

Ruby: Rest-client multipart upload to Google drive with metadata

I am trying to perform a file upload to google drive's API using Rest calls. The API says that if you want to name the file metadata must be passed and it should be uploaded as multipart.
I am getting a '400 Bad Request' error. I think that this might be due to having multiple content types using Rest client.
RestClient::Request.execute(
:method => "post",
:url => "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart",
:headers => {:Authorization => "Bearer #{access_token}", :content_type => 'multipart/related'},
:payload => {:metadata => "{'title' : 'testing'}", :file => File.new(file, 'rb'), :multipart => true}
)
Any help would be great! Thanks!
I believe, using the given library (rest-client), this is not possible as the request, according to Google's requirements, the multi-parts need to be ordered and must have the correct mime type for each of the multipart.
So, I'd say, the syntax you've used is closest to correct, but unfortunately the gem doesn't seem to support this [1] as of the time of this comment.
If you still are looking for a solution, the closest thing I found was digging directly into Google's API client library, where they hand-craft a multipart request with the help of hurley [2].
You can check the source code for some ideas.[3]
Hope this helps.
[1] https://github.com/rest-client/rest-client/pull/222
[2] https://github.com/lostisland/hurley
[3] https://github.com/google/google-api-ruby-client/blob/d2e51b4e7d4cb5a18cb08b2aed9c0d8ffff14b22/lib/google/apis/core/multipart.rb

Wildcard route in Grape

I'm having issues getting Grape to respond to a purely wild card route.
By that I mean that if I have a simple route defined as
get do
...
end
I need to respond to all potential requests made to the API. The situation being I need to parse the path and params and then work through a decision tree based on those values.
I've tried a few variations on the route definition, such as:
get '/*' do
...
end
get '/(*)' do
...
end
But to no avail.
I know that there is some support for regular expressions and route anchoring in Grape, but I've had no luck figuring it out.
Thanks!
You were close with the guess at the syntax, you just need to name the matching param:
E.g.
get '*thing' do
{ :thing => params[:thing] }
end
Using the * will make the param capture the rest of the URI path, ignoring / separators. But otherwise it behaves just like any other param.
Note this will only pickup within the Rack mount point at best, so if you have
prefix 'api'
version 'v2'
then it will respond to paths like /api/v2/hkfhqk/fwggw/ewfewg
If you are using this for custom 404 or other catch-all routes, then you need to add it at the end, otherwise it will mask more specific routes.

rails not routing https

The following rails routes.rb file
resources :aggregators, :constraints => { :protocol => "https"} do
collection do
get :confirm
post :send_sms
end
member do
post :confirmed
post :failed
post :cancelled
end
end
is not being called. When a form calls one of these actions,
<%= form_for(#aggregator) do |f| %>
the user gets bounced to the root page of the application. In comparing with and without the constraints, the non-https activity picks up
Started POST [...]
Processing by AggregatorsController#create as HTML
whereas the https version
Started POST [...]
Processing by AggregatorsController#index as HTML
So clearly the routing is missing the create action. (the bouncing back to home is an applicationController method which aplies a policy on the index action) I assumed it would be an integral part of resources. What am I doing wrong? Better yet I only want to invoke https on specific actions and would like to keep the focus on new, create and confirm...

Why am I getting a 405 on a POST request for JSON?

So I've got a Padrino app with a controller that looks roughly like this (simplified for brevity):
App.controllers :questions do
get :index, :with => :id, :provides => [:html, :json] do
# Stuff
end
post :index, :with => :id, :provides => [:html, :json] do
# Other stuff
end
end
If I hit "questions/1" in my browser, I see the HTML page for the given question. If I hit "questions/1.json", I see the JSON representation of the question. Exactly like I'd expect.
Now, if I submit a POST request to "questions/1" via a web form, it works. But if I try to send a POST request to "questions/1.json" (signaling that I want the response in JSON format—or at least that's how I thought it worked), I get a 405 Method Not Allowed.
I'm guessing there's something basic I'm misunderstanding here. What am I missing? More importantly, how should I define a route to accept POST requests and provide either HTML or JSON responses?
Well, I'm not really sure why this was happening; but for now I've gotten around the issue by setting the "ACCEPT" header in my POST request to "application/json" instead of tacking ".json" onto the end of the URL (and upon my limited internet research, this may be the preferred approach anyway).

Backbone JS and Ruby on Rails CRUD issue

This looks like an issue to me. Normal way Backbone works is using same URL and GET, POST, PUT and DELETE. But obviously:
1) All but POST methods need an ID either in URL or in request body
2) DELETE request can not contain body or some servers ignore body
So how can you make let's say a Ruby on Rails server app successfully work with Backbone without need to hack Backbone such as model.destroy() needs to have ID in the URL? And, as our RoR developer is telling me, normal way to do routes for PUT is to also have an ID in the URL?
There are 5 routes you need to implement to make use of backbone's default sync behavior. For a resource user, they are:
GET /user/ // Get a list of users
GET /user/:id // Get a single users by id
POST /user/ // Create a new user
PUT /user/:id // Update an existing user by id
DELETE /user/:id // Delete an existing user by id
I'm not very familiar with Ruby on Rails, but glancing at their documentation you could fulfill this specification with something like:
match "/user/" => "users#all", :via => :get
match "/user/:user_id" => "users#one", :via => :get
match "/user/" => "users#create", :via => :post
match "/user/:user_id" => "users#update", :via => :put
match "/user/:user_id" => "users#delete", :via => :delete
You should not have to hack Backbone for it to work with RoR. Backbone is smart enough to know (to a certain extent) what URL and what method it should use.
For example, for the initial fetch of a model, if you set url to '/tasks', it will do a GET request to '/tasks/id'. When you change that model, and call model.save, it will do a PUT request to '/tasks/id'. When you call model.destroy, it will send a DELETE request (with an empty body)
The one thing you do have to consider is the CSRF token. I suggest you include backbone-rails in your Gemfile. It includes some JavaScripts to help with Rails/Backbone integration.

Resources