Rails parameters from GET/POST - ruby-on-rails

I'm fairly new to Rails and am writing a login form. I have used form_tag to pass through the user's submission to the account controller. Now, I don't want the user to be able to enter their login details through a GET request, so how can I check that a certain param is either a GET or POST parameter?
Thanks in advance

In Rails you don't have specific POST or GET parameters. You do have a POST or GET request. You can check it like this in your controller:
request.post?
or you can check for other HTTP verbs: GET, PUT and DELETE:
request.get?
request.put?
request.delete?
For more info, check this piece of the documentation: http://railsapi.com/doc/rails-v2.3.8/classes/ActionController/Request.html

If what you need is to know the HTTP verb you can ask directly to request:
request.request_method

You could of course POST to a url that included a query parameter, so the selected answer might not be what you're looking for. Try checking if the parameter exists in the request arrays:
if request.GET.include? "param_name"
# do something
end
There's also request.POST and there are aliases (query_parameters for GET and request_parameters for POST) for both in ActionDispatch::Request:
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-GET

Related

In rails is 'method:' parameter used only for delete action?

I am new to Rails and came to know about the destroy action.When we write a destroy action for deleting something, in the link to delete it, we write the code:
method: :delete
So is the method parameter used only for delete, or is it used somewhere else too?
Thanks in advance.
By default (Incase if you don't mention method type) it take HTTP method type as GET
So explicitly for any other HTTP request you need to mention HTTP method type for request.
Destroy action(which is use to delete some record) should be delete type HTTP request. so in link it need to mention method: :delete otherwise it serve request as get. hopefully this will clear your doubt.
References: -
https://guides.rubyonrails.org/routing.html
https://guides.rubyonrails.org/v2.3/routing.html#restful-routes

Get referrer URL with parameters in Rails

I have a site with the basic rails scaffold, when a user deletes a record the default action is to redirect to the home page. However I would like it to return to the list the user was just looking at.
Right now I'm using request.referrer which is technically getting the referral URL but the parameters are not included...
In my rails logs I can see "Started GET /books/book_preview?name=Hunger+Games"
But request.referrer only shows "https://x.x.x.x/books"
I have also tried .original_url and .original_fullpath but those return the path of the current page for the record "/books/HungerGames". I also tried URI(request.referrer).query to at least just get the parameters but that threw an error.
I would like to get the previous path with the parameters like: /books/books_preview?name=Hunger+Games
Also this list is a remote partial that is rendered through JS. You can't see the URL in the browser URL bar only when highlight over it or look in the rails logs. It doesn't even show up in the request when i looked through it using request.inspect.
Thanks in advance for any help! Have been stuck on this all day!
request.referrer
It will give you referral url with query params as well.
You're not getting the query string from the URL, according to this answer (& docs), you need:
request.fullpath #-> book_preview?name=Hunger+Games
--
As an aside, if you're using this as a lists page, it should be okay. However, if you're wanting to pull specific book records, you'd be better using a member route:
#config/routes.rb
scope "/books" do
resources :book_preview, only: :show, param: :name #-> url.com/books/book_preview/:name
end
This would give you the ability to return a specific object for that book, negating any need to hack the request path etc.

Set params hash value using link_to without affecting url in Rails 4

When I submit a form, a number of parameters are set without showing up in the url.
I would like to do the same thing with link_to:
<%= link_to((purchase.paid ? 'yes' : 'no'), {action: :index, hidden_id: purchase.id}) %>
produces the url 'http://localhost:3000/purchases?hidden_id=1'. I would like to link to the url 'http://localhost:3000/purchases' while still setting params[:hidden_id] so I can access it in the controller, as if I had submitted a form.
My routes.rb file is as follows:
root to: 'products#index'
resources :products
resources :purchases
match ':controller/(:action/(:id))', controller: :shop, via: [:get,:post]
In answering this, is there anything I should know here about the difference in the way these two things are handled? Is it something about get vs post requests or is there some other principle involved which I'm not grasping?
Yes, it's to do with Get vs Post requests.
A Get request can only send parameters in the URL itself. A post request can also be sent to a URL that includes parameters in the URL itself, but it can also send parameters 'under the hood' so to speak.
So if your routes were set up to allow it, you could send either a get or a post request to http://localhost:3000/purchases?hidden_id=1, but only the post request could include additional parameters under the hood.
Anything else you should know about the difference in the way these two are handled? Yes. In most web frameworks, when you see the parameters server-side, they will be split up into GET params and POST params. Rails doesn't make this distinction, and puts them both in the same params hash. (I think this is silly, but whatever).
Also, a get request can be sent simply by entering the URL in your browser and hitting enter. A post request will generally only be executed by a user submitting a form on a web page. For this reason, get requests are not meant to change any content in your database. They should be for viewing information only. So, eg, if you have a button to delete a resource (eg. a blog post or something) it should be submitted via post. (more info on that at Why shouldn't data be modified on an HTTP GET request?)
Lastly, Rails provides an option in it's link_to helper to allow you to easily make the 'link' use a post request. See the method option at http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to. This basically uses javascript to prevent the normal action of clicking the link (which would be a get request), and submit a post request instead.

Passing parameters through OmniAuth

I need to pass some parameters to callback action. Judging from the source code, OmniAuth should add query string to callback URL but strangely it does not. When I open
/auth/facebook?from=partner
...and get redirected to Facebook, return_url is just
/auth/facebook/callback
...without any parameters.
After struggling with all the above answers, I figured out what to do regarding Facebook, which by default does not display the params in request.env["omniauth.auth"].
So -- If you are using a query string for the callback, similar to something like this:
"/auth/facebook?website_id=#{#website.id}"
The only way to get that website_id param is by using request.env["omniauth.params"]. NOTE: MAKE SURE YOU USE omniauth.params and not omniauth.auth -- this one tripped me up for a while.
Then, to test this out, you can inspect it within your controller action (notice the RAISE line...):
def create
raise request.env["omniauth.params"].to_yaml
# the rest of your create action code...
end
You should see your parameter there. Great. Now, go back to your controller and remove that RAISE line. Then, you can access the param as follows in your controller action:
params = request.env["omniauth.params"]
website_id = params["website_id"]
NOTE: in params["website_id"] you need to use quotes and NOT a symbol.
I guess the cookie thing works but why do all that when you can use the state variable as documented here: https://github.com/mkdynamic/omniauth-facebook
This is how I used it:
when creating the url you can just add state in the Query String and it will be available in the callback url as well.
user_omniauth_authorize_path(:facebook, :display => 'page', :state=>'123') %>
now the callback url will be
http://localhost:3000/users/auth/facebook/callback?state=123&code=ReallyLongCode#_=_
Now in the callback handler you can process the state
You can use the :params options, as in
omniauth_authorize_path(:user, :facebook, var: 'value', var2: 'value2' )
and later in the callback you can access request.env['omniauth.params'] to get the hash! :)
(copied from this answer)
What you want to do is dynamically set your callback to include the partner name in the url (not the url parameters), on a per authentication transaction basis, depending on which partner was involved. This means setting the callback url dynamically, for each authentication request. See this blog post to get started. The callback url automatically drops the url parameters, as you've noticed, so doing this with parameters won't work.
So, if instead of trying to pass the partner name/id in as a parameter (which is dropped), you structured your routes so that the partner_id and OmniAuth provider were part of the callback url, then you'd have something like:
/auth/:omniauth_provider/callback/:partner_id
...where a valid callback would be something like
/auth/facebook/callback/123456
...then you would know that a given callback came in from facebook, with partner id 123456
OmniAuth already has a built-in way to know where the user was, it's called "origin" as documented here:
https://github.com/intridea/omniauth/wiki/Saving-User-Location
You know, I think I might be trying to solve this the hard way.
Cookies might be the answer. I think you can solve this by having your login action store a cookie, and then redirecting to the proper /auth/:provider path for authentication, and when the callback is triggered (in SessionsController#create), you just read the cookie back to know where to redirect them to.
So, right now, your "login with facebook" link (or whatever you have you in your app) probably goes to /auth/facebook. Instead if you created a custom action like
POST /partner_auth
...and called it with the url...
POST example.com/partner_auth?from=partner&provider=facebook
Then you might have a controller like:
class PartnerAuth < ApplicationController
def create
cookies[:from] = params[:from] # creates a cookie storing the "from" value
redirect_to "auth/#{params[:provider]"
end
end
Then in the SessionsController#create action, you would have...
def create
...
destination = cookies[:from]
cookies[:from].delete
redirect_to destination # or whatever the appropriate thing is for your
# app to do with the "from" information
end
I tried to build a demo app to accomplish what I'd outlined in the other answer, but you're right - it was too complicated to try to dynamically inject a custom callback into the OmniAuth code. There is a configuration option to override the default callback, but it doesn't appear to be easy to set it dynamically.
So, it dawned on me that cookies would be way simpler, user-specific, and since you theoretically only need to store this from information for a very short time (between when the user tries to authenticate, and when the callback is triggered), it's no big deal to create a cookie, and then delete it when the callback gets hit.
Use the 'state' Variable. Facebook allows the user to set a STATE variable.
Here is how I did it, I appended the AUTH URL with ?state=providername
http://localhost/users/auth/facebook?state=providername
This param is returned to me at Callback as params['providername']
I devised the solution from the original Omniauth Path Method
user_omniauth_authorize_path(:facebook, :display => 'page', :state=>'123') %>

How to distinguish a request

I am creating an API and I would like to distinguish GET, DELETE, MODIFY, POST requests.
Is it possible to distinguish that from a controller?
For example:
Distinguish: (GET REQUEST)
GET http://myapi.com/POST/1234
From DELETE REQUEST
DELETE http://myapi.com/POST/1234
Can I do that from post controller?
Thanks
Inside a controller action method, do:
request.method
It's going to say which HTTP method was used.
You can also use:
request.get?
request.post?
request.delete?
And so on.
For full documentation on the class, check here.
If you map your routes RESTfully (see this tutorial), the DELETE verb on that resource will map to a different controller action than the GET request.
GET maps to show and DELETE maps to destroy.

Resources