Backbone JS and Ruby on Rails CRUD issue - ruby

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.

Related

Laravel. Conflict when building routes

There are two routes:
Route::get('/{article:slug}', [ArticleController::class, 'showArticlePage']);
and
Route::get('/{user:nickname}', [ProfileInfoController::class, 'getUserByNickname']);
Is there any way for each of the routes to perform its function?You can't change uri
For example:
domain.com/nickname => I have to get the user
There is a search in the table "users"
2.domain.com/my-first-article => I have to get the article
There is a search in the table "articles"
Note that each routes has its own controller and action, but they have a similar uri
You need something to distinguish them it'll be a lot more helpful. E.g use an # in front of usernames.
Another approach would be if you know for sure all slugs will have a hyphen, then you can chain ->where('slug', '...')
See https://pineco.de/handy-regex-constraints-in-laravel-routes/
Otherwise, it'll go through the first defined route.

Registering routes with Laravel but make them unaccessible

I am trying to make a single page CRUD application with Laravel. I will use ajax to create, edit and delete my entity, and also to render partial views. The corresponding controller methods will process the information and return the views.
I want to register the routes so I can call the different methods when necessary. I don't see any other way:
However, registering them so I can do something like this {{ Form::open(['route' => ['cities.store', $city->id]]) }} will allow access via the URL, and I only want to make those routes accessible through the tools I am going to create in that one page CRUD.
I can only think of applying a before filter, but what would be the filter? Also, any other ideas on how I should approach this situtation?
I've had to do something similar with a web service I created. Basically, I wanted only my app to be able to access the routes I created.
What I ended up doing was adding a hashed key to each request being sent, then checking for this key value in the controller. So, only if the key is present and matches the one sent would you then process the request.
Or, if you're using forms, you could do something like the following:
//check if request was sent from our form
if ( Session::token() !== Input::get( '_token' ) ) {
return Response::json( array(
'msg' => 'Unauthorized access attempt'
) );
}
Hope this helps.
another way that doesnt need tokens but is less secure, you got to know what you need,
is using laravels request information
if (Request::ajax())
{
//your action
}else{
//error
}
note this only works when your application always uses ajax you could even type this in your before filter and add it to all needed routes

Same Rails 4 routes for GET and POST requests

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"

Internal redirection in Padrino

Is there a way to internally redirect in Padrino? I am writing a RESTful service, no HTML response of browser client.
I have a resource, lets say, xyz.
MyApp.controllers :xyz
I have two routes in a controller:
put :index, :with => :xyz_id do...end
and
get :show, :map => '/xyz/:xyz_id' do...end
Now to simplify (and centralize) view (which is a JSON document) creation, I want to just internally redirect the control so that it processes the :show method after creating the resource. Hence, for a client of the service, PUT /xyz/1234 will create a new resource and return the same and GET /xyz/1234 will return the resource if it exists.
Is there a way to INTERNALLY (not a 302 response sent to the client) redirect to get :show method from the put :index method (after creating the resource)? Something like:
redirect (:xyz, :index, {:xyz_id => '1234'})
First of, you can put logic behind the showing data into separate function that you can call from both GET and PUT routes. If you really want to pass processing to a different route, you can do it with rack's call method:
put '/foo' do
# putting related stuff
call env.merge('REQUEST_METHOD' => 'GET')
end

Manual POST request

Scenario: I have logged into a website, gained cookies etc, got to a particular webpage with a form + hidden fields. I now want to be able to create my own http post with my own hidden form data instead of what is on the webpage and verify the response instead of using the one on the webpage.
Reason: Testing against pre-existing data (I know, I know) which could be different on each environment hence no predictable way to use it. We need a workaround.
Is there any way to do this without manually editing the existing form and submitting that? Feels a little 'hacky'.
Ideally, I would like to say something like:
browser.post 'url', 'field1=test&field2=abc'
I would probably switch to mechanize to muck around at the protocol level. Something like this added to your script
b = WWW::Mechanize.new
b.get('http://yoursite.com/current_page') do |page|
# Submit the login form
my_form = page.form_with(:action => '/post/url') do |f|
f.form_loginname = 'tim'
f.form_pw = 'password'
end.click_button
end

Resources