I am new to RESTful architecture or at least new to using it properly I have only had true experience with SOAP. I am having a problem wrapping my head around some things. I know there are other questions that are similar but none, that I have found, answer my question satisfactorily.
I am just starting this app so I want to get it started the right way and what I am looking at now is a user registration screen. I have two validation calls that occur before the registration form is even submitted. First I have a validation call that checks to make sure the email entered by the user is unique and second I have a validation call that checks to make sure an access code we provide to the customer exists in the database.
I currently have it structured as a POST (which I believe should be a GET) and I have an action argument that defines what I am wanting to do. So for the email I have an argument string such as
action=validateemail&value=email#email.com
and it is calling the User action of my MembershipController. I am entirely sure this is wrong as I should only be using the verbs GET, POST, PUT, and DELETE yet I am defining my own verb using the action argument.
Honestly, I don't know how to do this. I believe the User should be my resource but possibly for the email validation Email should be my resource. I guess what I am asking is how would you do what I am trying to do? I know some of you might just say do all the validation upon the submit, but I would prefer to do it both ways really. I would like the asynchronous validation as well as the validation I will perform when the user submits.
We do something similar and our resource is called "Account". For the validation I would do a GET for the Account specified and validate the HTTP return code. I would expect a 404 - Not Found to let me know the proposed account doesn't exist. If they passed in mangled data a 400 - Bad Request would tell you something was wrong. To create the Account a POST of the same resource would do. To do something like change a password, a PUT might be appropriate. I think that if you already are making a trip to the server, you might as well return the account(200 - Ok on the GET) if it exists to save yourself the second trip.
Related
I feel like I've seen this in many Rails apps, and it never made sense to me (but maybe that's because it's well past midnight and my brain is mush).
When I edit (for example) a user at /admin/users/20/edit, and I get a validation error, and the controller code is something like this:
def update
if #user.update(user_params)
redirect_to(some_path, notice: 'Record updated')
else
render("edit") # <<<<<<<<<<<<<<<<<<<
end
end
instead of going to /admin/users/20/edit, it shows /admin/users/20 in the browser.
This seems all well and good, but without /edit it is not a valid GET URI, so other code which is consuming the HTTP_REFERER, and which (naturally) expects it to be a valid GET URI will take the user to an error page.
In my case there is an internal gem which handles impersonation of users by admin users. Ending an impersonation takes the admin user back to the referrer, and if they have had the referer modified by a validation error, then they get an error.
I could
modify the gem to handle this case (a hassle, but perhaps necessary)
add a route to make this URL valid for editing without /edit (seems like it shouldn't be necessary, and seems a bit kludgey),
but I want to know if there is a reason this is happening. Is this in fact standard Rails behavior or have I overlooked something? If this is standard, is there a good widely-accepted fix? If it is not standard Rails behavior, where should I look for the culprit?
It's pretty normal behaviour because when you update a user you will do a PUTor PATCH to /admin/users/20. So if there is a validation error, you are rendering the edit template and the url stays the same (/admin/users/20)
You could do a redirect instead of render, but in that case you are losing some info about the validation error. Or you should send it a long with the redirect.
This is a common Rails beginner hangup and the key here is really understanding HTTP verbs, the concept of idempotency and Rails flavored REST.
The /new and /edit actions in Rails respond to GET requests. They are idempotent - the page will look the same to any visitor and if you reload the page you'll get the exact same page. They only serve to display a form in classical applications.
Updating resources done with PATCH /users/1 (or PUT in legacy Rails apps). These verbs are non-idempotent as they modify a resource. Unlike many other frameworks Rails uses the HTTP method to destinguish between different actions instead of using for example POST /users/1/update or POST /users/1/delete.
What you're doing when you call render("edit") is not redirecting the user back to the form. You're rendering a view and displaying the result of performing a non-idempotent action. This is not something that can be linked to as the result depends on the input passed in the request body and neither can you reload the page without resending the exact same request - and in this case sending the result again is not guarenteed to give the same result. Some browsers do not allow this at all and almost all will warn you.
This seems all well and good, but without /edit it is not a valid GET URI, so other code which is consuming the HTTP_REFERER, and which (naturally) expects it to be a valid GET URI will take the user to an error page.
This is an X & Y problem. The result of editing a record is not idempotent and thus cannot be linked to. Using HTTP_REFERER is in itself also problematic as its not guarenteed to be sent by the client.
While you can create a scheme to redirect back with the user input stuffed into the query string or the session this is the wrong answer to the wrong question.
where should I look for the culprit?
Whatever gem you're using might not be a good solution for the original problem - or even good at all. Impersonating a user might be a lot more fuss then just creating a separate endpoint for admins to edit users directly.
It certainly sounds like a very brittle solution.
To generalize this question I asked this morning, and please accept my apologies if this has been asked before and I simply don't know what to search for, but I'm curious how Rails handles the following situation:
Using Devise, I log in a user, with an ID of 2.
I click on a link that has been created to "edit my profile" (which simply would go to the /users/2/edit page).
Using Firebug (or something similar), I modify the form and change the action from action='/users/2' to action='/users/5'.
I change an element on the form, and click submit.
At this point, Rails appears to allow the submission and update user with ID 5 with my changes.
I'm guessing I'm not the first one to ask this question. It seems to me like Rails should handle this "out of the box", but I could be wrong. Does Rails handle this natively and I'm just missing something? Has this been asked before on SO or somewhere else that I'm missing?
A few things:
Don't create a route that accepts a DB id. Instead, make it something like /my_profile.
If an id is passed in the params, ignore it entirely in the controller. Instead lookup the current_user that is logged in and show them their own profile regardless of what profile/user id is passed in.
Finally, and possibly most important, use authorization (what a user is allowed to do) in order to disallow one user from editing another user's profile. Not to be confused with authentication (user logins/logouts).
With this approach it won't matter if the DOM is changed, because the server should never implicitly trust what is passed to it, which is the problem you're facing now. Any web/app server must always confirm that the parameters being passed to it are actually valid in the context of what the current user is allowed to do.
This idea that the server should never trust what's passed to it is a critical idea to apply to every single action in your app, without exception.
New to web development, my understanding is that GET is used to get user input and POST to give them output. If I have a hybrid page, eg. on StackOverflow, if I write a question, it POSTs a page with my question, but also has a text box to GET my answer. In my routes file, what method would the URL associated with my postQgetA() method specify - GET or POST?
From technical point of view you can use only GET to perform almost every operation, but...
GET is most common method and it's used when you ie. click on the link, to get data (and do not modify it on server), optionally you send id of the resource to get (if you need to get data of single user).
POST is most often used to sending new data to the server ie. from form - to store them in your database (or proccess in any other way)
There are also other request methods (ie. DELETE, PUT) you can use with Play, however some of them need to be 'emulated' via ie. ajax, as there is not possible to set method of the common link ie. to DELETE. It's described how to use non-GET/POST methods in Play! (Note, that Julien suggests there, using GET for delete action although is possible it's a broken semantics.)
There are also other discussions on StackOverflow where you can find examples and suggestions for choosing correct method for your routes.
BTW, if you sending some request, let's say it's POST you don't need to perform separate GET as sending a request generates a response in other words, after sending new question with POST first you're trying to save it to DB, if no errors render the page and send it back in response.
Im wondering how to handle missing request parameters in a struts2 action :
Let's say you have an action to view a user profile.
The action will show the profile of a given user according to the userId parameter.
How do you handle the fact that this parameter may be missing (if user load directly the action from the url bar or if he plays with tamper data addon ...) ?
I see several options but I wonder if there are other options and which one is the best :
In each action, on prepare(), check if the expected parameters are given, if not redirect
In each action, on the method that process the request, check that parameters, if not then redirect
I also thought I could use validators to make sure parameters are there but it only works for a form, doesnt it ?
If you have any idea or any point of view on this question, I would love to hear it
Thanks
Validation operates on request parameters--it doesn't matter if it's via a form or request parameters.
As long as an action has appropriate setters, which it would in this case, the default validation works fine. Determining if the user has the rights to access the profile in question may also be handled using a custom validator, probably one that uses existing business logic to determine access rights.
All of that, however, may be wrapped up using Spring Security, and eliminate the need for writing your own interceptor and/or validator. Which solution is the most appropriate depends on your actual needs.
How do miscellaneous account management pages fit into a RESTful design in Rails 3?
For example, a user registers (create action) and is then forwarded to a registration success page (? action) where they are asked to now verify their email address via a url with a token (emailed to them).
When they click the link in the email, technically they are "updating" their account as part of the verification process right? So I'm thinking that would somehow map to the "update" action but the update action is expecting a PUT request. Is that correct? How do you make that work via the email?
I'm also wondering how forgot password, reset password, etc also fit into a RESTful design? Just trying to wrap my head around this.
Just because you have a result design, doesn't mean you HAVE to restrict yourself to only CRUD verbs that map 1:1 to Get/Post/Put/Delete. That said, if you want to get really RESTful, you can start to think of some of these things in terms of being their own resources. For example user verification:
User signs up, and gets sent a verification email, you already have that all squared away RESTfully it looks like
Verification url looks like: http://app.com/user_verifications/new?token=foobar (GET)
They follow the url and maybe are presented with a "Hello Dan, welcome back! Click here to verify your account" at that point you submit a form to http://app.com/user_verifications to trigger the create action there. Now on the backend, you can perform whatever actions you want, updating the user, setting them to active, or actually creating a "UserVerification" model.
Not a perfect example, but the idea is that the RESTful interface you are providing has an additional resource, in this case "user_verifications" and a user is acting upon it via HTTP methods in order to achieve the user's goals. You can apply similar logic to reset/forgot password either with a "UserSession" type resource or even as specific as a specific "ForgotPassword" resource.
Success page is just create.html.erb file. Usually you are redirecting from create action, but here you can just render success template.
Verifying. If you want to stay REST you should add one more step: GET verify, where is the form with your token present, which will lead to PUT update action. User recieves a link to this page.
But I prefer to use simple GET request here, which will update information without any additional clicks.
The same way you work with restoring passwords and other functionality. You add a page to with form that gets email, then you send a letter with link to a page with form filled with tokens and so on.