Access old get parameters in URL after a post request - ruby-on-rails

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.

Related

How does edit_password_reset_url(some_id_here) resolve to https://example.com/password_resets/some_id_here/edit?

I've been looking at Learn RoR tutorials and we have this route:
edit_password_reset GET /password_resets/:id/edit(.:format) password_resets#edit
I do not understand how this line:
<%= edit_password_reset_url(#user.reset_token, email: #user.email) %>
Will translate into:
https://example.com/password_resets/<some token here>/edit?email=<user email here>
More specifically, how does rails know that the first param (#user.reset_token) is suppose to go into the :id portion of the url?
The controller PasswordResetsController's edit function is defined but blank.
The first argument passed to edit_password_reset_url replaces the :id parameter you see when running rails routes (/password_resets/:id/edit(.:format)). The docs on this can be found here.
You can actually update this to use a more relevant parameter, such as :token in your case, by using:
resources :password_resets, param: :token
The url helper also takes a hash of arguments where you can provide additional params, as you're doing with email.
Slightly unnecessary additional explanation
Were you using a nested route, say, edit_user_password_reset_url, this would product something akin to users/:id/password_resets/:token/edit(.:format). The same still applies - the first arg of the helper fills in the variable parameters, though would now take an array, i.e. edit_user_password_reset_url([#user.id, #token])
/end slightly unnecessary additional explanation
The edit action in your controller can be blank, though typically assigns a resource to be used in the edit view (/password_resets/edit.html.erb or similar). This generally contains a form that, when submitted, will hit the update action of the same controller.
So, in this case, you may want the edit action to contain the following:
def edit
#user = User.find_by_reset_token(params[:id]) # or params[:token] if you update as above
end
Then, in your edit view, you can include a form allowing the user to reset their password.

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

wrong number of arguments (given 0, expected 1) passing parameter into helper

module ProfilesHelper
def accept (invites)
invite=invites.find(id: '1')
invite.accept= '1'
invite.save
end
end
The user needs to click a button to accept or deny an invitation they have received. I created this helper method, it's suppose to find the user's invite and then set it's accept boolean to 1. But I get "wrong number of arguments (given 0, expected 1)"
Views:
<% #invites.each do |invite| %>
<%= link_to "Accept", accept(invite) %>
<% end %>
How do I pass the invite object into the accept helper?
I think you're misunderstanding the purpose of helpers. With the way you're using this code, the invite will be accepted when the page is viewed, not when the link is clicked.
Helpers are there to help you lay out the page. Either by abstracting logic away from the view, decorating things, formatting numbers into currency, or a million other things. They are not for handling requests.
You shouldn't be using standard GET requests (an anchor tag) to make changes to your data set. They should come via PUT, PATCH, POST, DELETE requests.
What you need here is to either use a button element, or change your link to submit the request using a PUT or PATCH verb. Then, using a suitable route to receive the request to accept the invite, add an action to your controller to handle this request.
Then in your controller you can do something like this:
def accept_invite
#invite = Invite.find(params[:id])
#invite.accept!
end
Which allows you to move the business logic of handling that acceptance into the model:
class Invite
def accept!
accept = true
save
# You might want to do other things here, like email them a confirmation etc.
end
end
This way, your controller can worry about just handling the request, and the model can worry about how to handle actually accepting an invite.

Is it safe to populate forms with params values?

I am using a form to filter records with fields not linked to an AR object. When form is submitted, I want to show records and populate the form with previously entered values so the user can see filtering parameters.
Form example:
= form_tag businesses_path, method: 'get' do
.field
= label_tag :title, 'Title'
= text_field_tag :title, params[:title]
= button_tag do
'Submit'
I'm thinking of using params to populate form inputs but not sure if it's safe? Or maybe there is a better solution?
Since we're dealing with RESTful interfaces with Rails the params hash is in essence the data in the message between the front end (browser) and the back end. It is there to be used to relay data between the user front end and your controller at the back-end. The params hash is one of the most important and versatile tools in RoR.
From the Rails guide: http://guides.rubyonrails.org/action_controller_overview.html#hash-and-array-parameters
You will probably want to access data sent in by the user or other parameters in your controller actions. There are two kinds of parameters possible in a web application. The first are parameters that are sent as part of the URL, called query string parameters. The query string is everything after "?" in the URL. The second type of parameter is usually referred to as POST data. This information usually comes from an HTML form which has been filled in by the user. It's called POST data because it can only be sent as part of an HTTP POST request. Rails does not make any distinction between query string parameters and POST parameters, and both are available in the params hash in your controller:
So use the params hash; it is a sound method for caching user input and re-displaying it, as was your question.
Caveat
Of course, if you're displaying from the hash and not the database store itself, you may encounter data synchronization problems. But as far as your specific question, I'd say use the params hash without a second thought.
It's absolutely fine. Rails will sanitise anything on it's own. Just don't call params[:title].html_safe when you printing "raw" user input.
You can store that params in a instance variable in respective controller action like flowing in controller.
def test_action
#title = params[:title]
end
And then set #title as field value as flowing
= text_field_tag :title, #title

How do can you make redirect_to use a different HTTP request?

At the end of one of my controller actions I need to redirect to a page that only accepts put requests. I have been trying to figure out how to get redirect_to to use a put request but to no success.
Is this possible? Or is there another way to accomplish this?
I don't think you are able to do this, and I suspect that the limitation is part of HTTP itself.
When using redirect_to - the redirection happens as a "302 Moved" header unless otherwise specified in the parameters.
Having a look at the HTTP Spec itself doesn't reveal any way to change the type of request the browser makes via redirect.
HTTP Redirects:
This class of status code indicates
that further action needs to be taken
by the user agent in order to fulfill
the request. The action required MAY
be carried out by the user agent
without interaction with the user if
and only if the method used in the
second request is GET or HEAD.
I think you may need to use JavaScript to achieve this functionality, or perhaps rethink the flow of control in your application.
If the action is in the same controller as where you're trying to redirect from, simply call the action and render the template like so:
def show
index
render :action => "index"
end
If it's not, then I don't know how you do that.
Ok, so I found a solution to my problem. I found a very good write up on the situation here. My implementation looks like this:
private
def redirect_post(redirect_post_params)
controller_name = redirect_post_params[:controller]
controller = "#{controller_name.camelize}Controller".constantize
# Throw out existing params and merge the stored ones
request.parameters.reject! { true }
request.parameters.merge!(redirect_post_params)
controller.process(request, response)
if response.redirected_to
#performed_redirect = true
else
#performed_render = true
end
end
Then I called this method like this:
redirect_post :controller => 'registrations', :action => 'order', :_method => 'put', :authenticity_token => params[:authenticity_token]
So I was able to 'fake' a put request by making a post request (using redirect_post) and then assigning 'put' to a _method param. If you look at a normal put request all it is a post from a form with a _method param. So its a bit hackish but it gets the job done.
Also, you have to make sure that when you call redirect_post the values of your hash are strings otherwise errors will be thrown.
You could redirect to a different page that issues the put request from the client, using Javascript.

Resources