Is form data passed through session or params? - ruby-on-rails

I am not understanding the difference between session and params in the following application.
A user submits a new movie form. How would the associated controller access the title of the movie?
session['title']
session.title
params['title']
params.title
All of the above
Based on the StackOverflow answer at Difference between session and params in Controller class:
params live in the url or in the post body of a form, so it vanishes as soon as the query is made.
Session persists between multiple requests (the info are often stored in cookies but this depends on your configuration).
To be short:
params: one request only (creation of one object, access to one particular page)
session: info to be persisted (cart, logged user..)
I chose (1) session ['title'] on the quiz and got the answer wrong. I chose (1) because I thought it involved accessing information that had to persist.
Am I misinterpreting the question and maybe this falls more under "one request only" so the answer should be (3) params['title']?

To attempt to answer your question in the context of this quiz instead of just in the context of code, consider where it says that:
params live in the url or in the post body of a form, so it vanishes
as soon as the query is made.
Now consider that the question itself says:
A user submits a new movie form. How would the associated controller
access the title of the movie?
So the question is saying that the user interacts by filling out a form which is then posted to the server. This is exactly the "post body of a form" mentioned in your notes.
So the correct answer is 3) params['title'].
Now, once this data is accessed, it CAN BE PLACED into the session, but that's for the developer to do or decide, and that's not really within the scope of what's being talked about here.
You also know that, in the context of this question, the session is not what's used because your question only refers to a single request: the sending of the form. If your question referred to data sent from the form that had to persist over a few more requests (such as a multi-page form), then the session might come into play.

Before access data you need to put it. In default rails generated forms all data is send in one request in params. If you have form that points to User#create action and have 'name' input, you will have params['name'] in User#create action.
Session is another thing. It's hard to find sessions in standart generated rails scaffold. You can access session as a hash. session['name'] will store name between requests. Read more
So, params are are generated for one request - to transfer data from user to server, sessions are used not for transfer data, but for store it.

Related

Adding User-Agent & IP to a stored Session -RecordNotSaved -Rails

I'm currently building an in-house analytics system which tracks where a visitor clicks throughout each session, whether they are logged into a User account or are a visitor without an account.
I am currently saving my sessions to the database thanks to changes made through sessions_store.rb, however in addition to the session_id, I am trying to figure out how to add both UserAgent details and a visitor's IP to the sessions table.
I've tried a couple solutions but all have failed - my current solution appears to be the closest, however I keep encountering an ActiveRecord::RecordNotSaved error after updating the Session's attributes.
I am currently using a before filter in application controller:
before_filter :set_useragent_and_ip_in_session
def set_useragent_and_ip_in_session
if session
sess = request.session_options[:id]
#session = Session.where(session_id: sess).first
#session.update_attributes(:ip=>request.remote_ip, :user_agent=>request.user_agent)
#session.save!
else
end
end
I've inserted a debugging statement in my views and have played around the code in pry - the #session is valid and displays the #session.user_agent properly .... however when saving to the DB it justs rollsback.
When I use save!, I receive a Completed 422 Unprocessable Entity in the logs in addition to the following (pasted to gist to conserve space):
https://gist.github.com/anonymous/8019c2426334f395a5fd
Thanks! Any help would be very appreciated.
I would recommend rethinking your schema. A session can last many requests and you want a record per request. Also notice how your moving data off the request object and trying to store them into a session table. Instead make your very own request table and make a before filter that moves all the data you want from the request object to the request table. Now a session will have many requests.
I'm not sure why your record isn't saving however I would wager naming a model Session is conflicting with rails. By that same token when you make your request table you should give it a unique name like maybe SessionMeta and RequestMeta. Then SessionMeta could have many RequestMeta.

Passing a token securely from one controller method to another

I want to generate a random token for my user. For UX reasons, I want to generate this token in MyController#new in order to show it in new view. Then I need to pass it to create method. However, I want to prevent user from changing it.
I know of 3 ways to do it:
pass it as hidden field
pass it through sessions
write it to database, marked as incomplete, then set it to complete in create method
The first two approaches are not secure, while the last is overkill.
Is there a way to securely pass a parameter from new to create method in controller?
Sessions in Rails and # and above are very very secure because they are hashed. The official library says there are no practically evidences of session hash been compromised so the user can only delete that token from the browser but they can't change it to a logically correct value.
What you can do is save the value in sessions and make a hash value yourself from that token and save it also in session then on the receiving side you can regenerate the hash from the session and verify the value.
no user can edit both the session values that they match. If its not matching you can discard the values and throw to an error page.
I hope i answered you, if there is any misunderstanding pls ask.

Backbone.save POST instead of PUT

just a short question:
Having the new instance of a model and issuing a model.save() with URL set to /api/store/category, Backbone issues a POST. According to my knowledge, it should use PUT, like mentioned in this "PUT or POST: The REST of the Story" blog post.
Who is right? BB or this article's author?
According to Backbone documentation, saving a new model will result in a POST request, and saving an existing model (having an id) will emit a PUT request.
save model.save([attributes], [options])
...
If the model isNew, the save will be a "create" (HTTP POST), if the model already
exists on the server, the save will be an "update" (HTTP PUT).
And if you are wondering if Backbone should use a POST for creation, check
PUT vs POST in REST
RESTful web services on Wikipedia
In the light of these articles, I'd say that, in the context of Backbone, the verbs are correctly used:
saving a new model causes a change in the system, a new URL is added, the action is not idempotent, it should be a POST,
saving a known model replaces a resource at a given URL, the action is idempotent, it should be a PUT.

Render w Params or Redirect w Errors in Ruby on Rails

I am using ruby on rails and have things on my site that users can click to save and they are redirected to a page with both a login and a signup so that the user can continue with either option and save the content. The creates a problem for showing the proper user validation errors, b/c I need to use a redirect_to users/new in order to pass the params with the object id that the user is saving and if I use render :new, the errors are displayed but the object id is lost. Anyone have any solutions for this?
Store the original item id in the session, proceed with your normal login/signup process, when that completes, if there is a save item in the session, redirect to the action that handles the save (it can now grab the item id from the session and proceed).
"Out of curiosity, what is wrong with saving the object itself in the session? That way I wouldn't have to perform a second database lookup to find the object again." --TenJack
(this should probably be a new StackOverflow question)
Saving an item in the session is a Bad Thing - because the moment you migrate your model object (eg to add a column or something similar), the data in the session is now no longer a valid object of the model's type. eg it will still have the old attribute-list instead of the new one... and it will appear as an invalid object.
This is why it's best to store only the id - because you will fetch a fresh, correctly instantiated object from the db.

Rails best practice for having same form on multiple pages

I am developing an Rails 2.3.1 Web site. Throughout the Web site, I need to have a form for creating Posts on various pages (Home page, Create Posts page, Post listing page, Comment listing page, etc. -- suffice to say this form needs to be on many pages served by a variety of controllers). Each of these pages displays a wide variety of other information that is retrieved in the corresponding controller/action. Ex, the home page lists latest 10 posts, content pulled from the DB, etc.
So, I've moved the Post creation form into its own partial, and included this partial on all the necessary pages. Note that the form in the Partial POSTs to /questions (which routes to PostsController::create -- this is default rails behavior).
The problem I am running into is when the the Posts form is not completed correctly, by default the PostsController::create method render's questions/new.html.erb, even if the form was submitted from the home page (/home/index.html.erb).
I tried changing the form in the partial to submit the "submitting_controller" and "submitting_action", and in PostsController::create, when #post.save? == false, I render action => "../submitting_controller/submitting_action" (Which is slightly hacky, but lets you render actions from non-PostsController's).
This seemed to work OK on the surface. The incomplete form was rendered in the view that submitted it with all the correct #post.errors message, etc. The problem was ALL the other data on the pages didnt show up, because the actual submitting_controller/submitting_action methods weren't called, just the associated view. (Remeber, I did a render which preserves instance objects, rather than a redirect_to which does not preserve the #post instance object which has all the error messages and submitted values.)
As far as I can see I have two options:
1) I can store the #post object in the session when #post.save? fails in PostsController::create, redirect_to submitting_controller/submitting_action, at which point i pull the #post object out of the session and use it to re-populate the form/error messages. (As far as I understand, storing objects in the session is BAD practice in rails)
2) I can move all the logic used to pull non-post creation form data from the various submitting_controller/submitting_action, put it in the ApplicationController, create a giant switch statement in PostsController::create for submitting_controller/submitting_action and call the methods in the ApplicationController to grab all the extra data needed for each submitting page's render.
Thoughts on the best way to do this within Rails?
By any chance is your Post model in a belongs_to relationship with each model who's controller you'll be using to render your form? Are you doing any special processing in the Post controller beyond Post.create(params[:post])?
If you answered yes to the first question and no to the second, you could get by with minimal mangling by adding accepts_nested_attributes_for to each of the controllers on which a user can create a post.
Regardless, Robertpostill is correct in that this is probably when to start looking at AJAX, to just replace the section of the page. The only problem is what to do if a user has javascript disabled. Personally I like to do design for the non-javascript case and add convenience methods.
As for thoughts on what you consider your two options,
1) I've used this method to store a shallow copy of an object in the flash hash. Preserving it across redirects. However this might not work for you given the variable nature of posts. As you can only send about 4K worth of data, and that includes other information in addition to your shallow copy.
2) See robertpostill's response
This is about the point that you move from full page updates to updating sections of a page through the use of AJAX. There are a bunch of things you should consider but the most rails-esque approach would be to split the response between an AJAX response and a plain HTML response. Check out this ONLamp article, this register article or the awesome agile web development with rails book. Essentially your controller renders a new div replacing the old div containing the result of submitting the partial.
In your question you mention two approaches and so I'll try and give you some pointers on why and why not here:
Option 1) Ths option is not so bad with a couple of tweaks. The main tweak is is to store the object in a serialized form in the DB. Then simply pass around the ID of the serialized object. Your upsides are that the session data gets persisted so recovering a a session is neater and your session stays light. The downside of this is that having a bucket of session cruft in your DB will pollute your app and you'l need to do some thinking as to how you expire unused session cruft from the DB. I've never seen this end well...
Option2) Eeek not inside the application_controller! :) Seriously, keep that as your weapon of last resort. You can pop things insde the helpers though and get access to those methods inside your controllers and views. However the testing of that stuff is not so easy so be careful before choosing that route. Switch statements can be replaced in OO apps with a little thinking, certainly in his case you can use option hashes to get a railsy way of having some smarts about the state of the app at the time the request is made.

Resources