How can I hide params in view's url? - ruby-on-rails

I'm passing a change id as a parameter with a link_to:
<%= link_to 'Change', my_service_path(change: '1234567890'), method: :get%>
In the controller I have:
def my_action
if params[:change]
...
params.delete :change
end
But when the view is displayed I still see
<view url>?change=1234567890
How do I prevent ?change=1234567890 from showing in the url?

That's because params is an instance of ActionController::Parameters, which was specifically created because people were treating the params object as a hash, as you're attempting to do.
As #arieljuod suggested, you'll have to convert your route/link to use a POST request instead of a GET request. That way the params will be sent along with the HTTP headers instead of showing up in the URL bar as a query string.
So in your case:
<%= link_to 'Change', my_service_path(change: '1234567890'), method: :post %>
...and make sure your route is configured to respond to a POST request

What you're trying to do, "Change", says to me you're trying to modify the state of a resource. In RESTful design, you should be PATCHing, not GET'ing.
The way you'd hide the params is to create a form, put change in a hidden field, and submit the form as a PATCH request using a button_tag.
In Slim, it would look like this:
= form_tag(url: my_service_url, method: :patch) do
= hidden_field_tag(:change, "123456789")
= submit_tag("Change")
On your website, it will look just like a regular link - but instead you are instructing the Rails server to EDIT the resource, not GET it.

to answer your question in the comments:
How will use of POST or a form prevent the query parameters from showing in the > url?
If you send a POST request, your request will have a body, too. So in the GET request from your link will send the change information via the url. In a POST request (use button_to or form) it will send via the body and not displayed in the url. You can then still access it via the params

Related

Access old get parameters in URL after a post request

I have a form in RoR with a controller action that looks up a record via the get parameter.
def respond
if request.post?
# Submit logic here...
# cannot lookup this way to fill the form out again
# #current_message = Saved_message.find_by_id(params[:msg_id])
elsif request.get?
#current_message = Saved_message.find_by_id(params[:msg_id])
end
end
I can't use the params[:msg_id] to lookup the message again because it's a post request and I don't resend the get parameters. However, the get parameters remain in the url such as .../messages/respond?msg_id=2. I can get around this by passing in a hidden field with a different parameter name like <%= form.hidden_field :msg_id_2, value: params[:msg_id] %>. Then I can lookup the #current_message via the params[:msg_id_2]. However, I don't like this solution. Any advice to access the now inaccessible get parameter?
you should use RESTful routes so that you do not have to care about such issues.
since you are not posting much about the actual code or problem you are trying to solve, i can just assume what might be the issue here and how to solve it.

How does the params method work?

I have been trying to figure out how the params method works and I'm a bit stuck on the process.
For example, if a user clicks on a certain blog post in the index page, I guess that the link_to method calls the Post controller and the show action along with its block #post = Post.find(params[:id]) and then goes to the database to find the post and the view displays it.
So my missing link seems to be when is the post id passed into the params method?
Because the others already explained about params, I'm just going to answer directly a question of yours:
when is the post id passed into the params method
I think it's best explained with an example; see below:
say that you clicked a link:
/posts/1/?param1=somevalue1&param2=somevalue2
The Rails server receives this request that a client wants to view this GET /posts/1/?param1=somevalue1&param2=somevalue2 address.
To determine how the Rails server will respond, the server will first go to your routes.rb and find the matching controller-action that will handle this request:
# let's say your routes.rb contain this line
# resources :posts
# resources :posts above actually contains MANY routes. One of them is below
# For sake of example, I commented above code, and I only want you to focus on this route:
get '/posts/:id', to: 'posts#show'
From above notice that there is this :id, Rails will automatically set params[:id] to the value of this :id. This is the answer to your question where params[:id] comes from.
It doesn't have to be :id; you can name it whatever you want. You can even have multiple URL params like so (just an example):
get /users/:user_id/posts/:id which will automatically set the value on params[:user_id] and params[:id] respectively.
In addition to this URL params like :id, Rails also injects values to params[:controller] and params[:action] automatically from the routes. Say from the example above, get '/posts/:id', to: 'posts#show', this will set params[:controller] to 'posts', and params[:action] to 'show'.
params values also comes from other sources like the "Query string" as described by Mayur, and also comes from the body of the request, like when you submit a form (the form values are set within the body part of the request) and like when you have JSON requests, which all of these are automatically parsed by Rails for your convenience, so you could just simply access params and get the values as you need them.
Params are hashes in ruby with Indifferent access which means,
hsh = {"a" => 1, "b" => 2}
Consider this hsh as params returned from a POST request from browser, it's a key value pair with keys as string. Since it's a params so the values can be accessed as
hsh["a"]
=> 1
hsh [:a]
=> 1
params are formed on the client where the interface load, consider a form which has a submit button. When you press submit, the data filled in form or any hidden textboxes are formed into a hash and passed across the request. This when received on server end will be called as params or request params.
For Get requests: data send across the url will be read as params on backend.
GET: http://www.abx.com?user=admin
params on backend: {"user" => "admin"}
This will be displayed in rails server logs
For Put request: data send across the body will be called params.
PUT: http://www.abx.com
data: {"user" => "admin"} Client side
params on backend: {"user" => "admin"}
This will be displayed in rails server logs
How does the params method work?
The params come from the user's browser when they request the page. For an HTTP GET request, which is the most common, the params are encoded in the URL. For example, if a user's browser requested
http://www.example.com/?post=1&comment=demo
then params[:post] would be "1" and params[:comment] would be "demo".
In HTTP/HTML, the params are really just a series of key-value pairs where the key and the value are strings, but Ruby on Rails has a special syntax for making the params be a hash with hashes or array or strings inside.
It might look like this:
{"post"=>"1", "comment"=>"demo"}
Link to Rails Guides on params: guides

Instagram API bad request : Please supply a valid action from the following: follow, unfollow, approve, ignore, block, unblock

I can't manage to send the action "follow" as postdata when I'm doing a POST request to the Instagram API. I'm trying to make a button_to in my rails app.
Here is the erb code :
<%= button_to "Follow", "https://api.instagram.com/v1/users/*[user_id]*/relationship?access_token=*[token]*", data: {action: "follow"} %>
The by default method for Button_to is POST so I don't need to specify that. And I have to send the "follow" action in the request body, but I don't see how.
Any help ?
You should just be able to add the Params to the url, like so:
?access_token=*[token]*&action=follow

Params array being replaced by controller and method

Im trying to retrieve the post parameters in my RoR app. However when i print:
params
It responds with
{
"action":"new",
"controller":"question"
}
Which is simply the controller and action.. How do i reference the post variables from the controller?
In my log, im getting the error: WARNING: Can't verify CSRF token authenticity
That is how you get post variables. If they're not there then there's a problem with your form or whatever is making the request.
Ditch your custom route match "/new/question" => "question#new", :via => :post You don't need it and it's just confusing matters. new actions don't accept params and should ONLY respond to GET requests.
Just send an HTTPPOST request to your/url/questions and rails will know to call the create action and you can pass in whatever params you need.
The new action is for rendering a form not for accepting POST requests.
Likewise if you send a PUT request to your/url/questions rails just knows to call the update action in the questions controller. That's the whole point of RESTfull routes.
Dude, are you including the "csrf_meta_tags" in your layout?
<%= csrf_meta_tags %>
If not, then rails will ditch all POST parameters...

how can I hide params I transmit to a method (like form_for seems to do)?

I've been searching for hours now and haven't found anything that helps.
What I want to do:
I need to call the check_login-Method (as below), which needs parameters.
redirect_to check_login_users_url(
:user => {:name => input[1], :password => input [2] },
:stylesheet => 'scaffold',
:method => :get)
The point is that these params are sent in the method-call as in the "Redirected to"-line below.
Processing ApplicationController#execute(for 127.0.0.1 at 2009-12-19 00:28:40) [POST]
Parameters: {"command"=>{"line"=>"log dodo wg"}, "authenticity_token"=> <...token>}
Redirected to http://localhost:3000/benutzer/check_login?method=get&stylesheet=scaffold&user%5Bname%5D=dodo&user%5Bpassword%5D=wg
Completed in 9ms (DB: 0) | 302 Found [http://localhost/execute]
I want to prevent rails from putting the params into the url and pass them hidden instead.
When I send a form created with form_for, there's nothing in the url, so I assume it must be possible.
Please tell me how to do that.
Steps tried
I have tried different "html-verbs": get, put, post - no difference. Though the call of check_login is really short the url-with-params shows up in my Console
create an instance variable and pass it as param (strange, didn't work either)
watch form_for working – without results, got no clue
//edith:
Thanks for all your help so far. Perhaps I didn't specify my problem in enough detail.
I've got a text_field in which I enter short commands (experimentally). Its form calls execute in AppController, which in case of login-data performs redirect_to check_login. I don't need to access a webpage, I simply want to run the method. I liked the idea of putting it into :flash, but I'm wondering if there's a "neater" way to do pass the data hidden.
TL; DR Version: Use a form.
You're never going to be able to fully hide parameters, tools can be used to monitor requests and view the post data/parameters. You could however obfuscate it with an encrypted session. Also it appears that you're sending login info via a GET request, this is generally a bad practice.
That said...
What is going wrong for you is that you're not generating any post data with link_to :method => :post. link_to will use what ever parmas you give it to generate the url. Wheres forms will send all the params generated by the form as POST data to the url generated in the form_for call.
Upon receiving a POST request, Rails will merge parameters routing picks up from from the URL with the post data it receives into one params hash.
As in POST to
http://localhost:3000/benutzer/check_login?stylesheet=scaffold&user%5Bname%5D=dodo&user%5Bpassword%5D=wg
produces the same params hash in the receiving controller action as a POST to http://localhost:3000/benutzer/check_login with the following data:
stylesheet=scaffold&user[name]=dodo&user[pasword]=wg
There will be no distinction in the server log between the two requests.
If you look at what form_for is doing, it submits POST data built from the form inputs to the url generated by the arguments.
form_for #user, create_user_url(:stylesheet => "scaffold") do |f|
f.text_field :name
f.password_field, :password
end
This form will submit the form data to the url generated from the options. In this example the url is: http://localhost:3000/users/create?stylesheet=scaffold and the form data is:
user[name]=name_field_value_at_submit&user[password]=password_field_value_at_submit
link_to will not populate post data for you. You must either do it through a form or with javascript. The link_to documentation contains an example of doing this with javascript. Look for how the destroy with :onclick is handled.
If you really don't like buttons, you could use link_to_function to submit a form.
Replace
:method => :get)
with
:method => :post)
What's the difference between :get and :post? Read Methods GET and POST in HTML forms - what's the difference?
With form_for you create form which is then POSTed to server, that's why you don't see parameters in url - they're in http request body. But it is not possible to redirect user's browser from some action in controller to make another POST - if it would be possible, then I could redirect user to (for example) email change form of gmail or other forms. You can only redirect user to other site, which user's browser then GETs.
If you really don't want to show parameters in url, and both actions are in same application, then you can store those parameters in session or flash store, and retrieve in next request after redirect.
You can use Ajax request to send form data to action :
In some cases its not good to change :get into :post.
For instance in case of Controller's :index action its not good approach to use :post
So Use ajax call to submit form and update only dynamic content of the page.
In js.coffe script file
$ ->
$("#button-id").on "click", (ev) ->
$.ajax
type: "GET"
dataType: "html"
url: "/horoscope_dailies"
data:
date: date
success: (data) ->
$("#index_content").html data
error: (object, error) ->
console.log error
In your controller action
render partial: 'partial_name' if request.xhr?
In your view file:
%div{:id => 'partial_content'}
= render 'partial_name'

Resources