What is the use of request.referer? - ruby-on-rails

I want to know what the following code does. What is the use of request.referer?
#board = request.referer['dashboard'] if request.referer

request.referer gives you the previous URL or / if none. It is usually used to redirect the user back to the previous page (link)
More information here
Regarding your question, it is simply returning 'dashboard' if found in request.referer. Look at the following example:
> str = "hello world!"
=> "hello world!"
> str['hello']
=> "hello"
> str['lo wo']
=> "lo wo"
> str['foo']
=> nil
However, you should not depend on this method to redirect your user back. You can do this in your controller instead:
redirect_to :back

request.referer gives you the previous URL or / if none
In library you can see:
def referer
#env['HTTP_REFERER'] || '/'
end
You can use the referer technique for this, but you'll have to capture it when entering the form instead of when the form is submitted. Something like this:
<%= hidden_field_tag :referer, (params[:referer] || request.env['HTTP_REFERER']) %>
Then you can use params[:referer] in the controller to redirect back.

Related

Rails: Conditional redirect in rails app controller

I have an action in a controller that I call from two different views. In each case, I want the action to redirect back to the page on which the link was clicked. At the moment I am doing this...
In this view I am passing a parameter like this...
%a.showtooltip#wprofile{:href => idea_vote_up_path(#idea, :source => 'idea'), :title => 'Awesome idea - vote up !', }
and in the controller...
if params[:source] == 'idea'
redirect_to idea
else
redirect_to ideas_path
end
This works fine, but does not feel elegant, especially as it ends up being in a few actions. Is there a better way?
You can rewrite it in following way:
redirect_to params[:source] == 'idea' ? idea : ideas_path
If you want to redirect back to the page (refresh current page)
redirect_to request.referer
Store the referrer in the session like so session[:previous] ||= request.referer and use it as redirect_to session.delete(:previous)
I find that a good way is to have a hidden input with the value you'd like to be as the return url. Seems like an easily manageable solution and has worked for me. This way you can create the hidden input in 1 or 1000 views and have a single line of code in the controller to do the redirects. I can't immediately think of what the cons to this approach would be.
In form
hidden_field_tag(:redirect_to, params[:redirect_to]) # in the form that is to be submitted, value determined by a query string
hidden_field_tag(:redirect_to, "/a/direct/value") # in the form, value specified directly
In controller
redirect_to params[:redirect_to].presence || idea_path(#idea)
Didn't test the code and don't know ruby sups well so double check but the logic should stand. The ".presence" takes care of situations where you don't want a custom redirect to and have no hidden input to specify.

current_page? wrong after POST

I'm displaying certain items in my navigation bar depending on the current page. When I go to my sign in page the correct items are displayed. If I sign in with an incorrect password the items change and are incorrect.
In my html I check if (current_page?(new_user_session_path))
After the incorrect password is submitted and the page reloads this condition isn't returning true and it's displaying the wrong items in the navbar. I looked through the requests on the server logs and I'm guessing it's because the second time around the page loads after a POST (the unsuccessful password submission). Is there a different path I need to check for the second time?
Expanding on Scott's answer, you could create a helper in app/helpers/navigation_helper.rb for instance, like so:
module NavigationHelper
def current_location?(*args)
options = args.extract_options!
options.each do |key, val|
return false unless eval("controller.#{key.to_s}_name") == val
end
true
end
end
And use it this way:
current_location?(controller: 'my_controller', action: 'new')
current_location?(controller: 'my_controller')
current_location?(action: 'new')
In your view you can then do something like:
# Change this according what your really need
if current_location?(controller: 'sessions', action: 'new')
Hope it helps ; )
If you look at the source code of current_page?, it always returns false if the request's HTTP mode is anything other than GET or HEAD:
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-current_page-3F
def current_page?(options)
unless request
raise "You cannot use helpers that need to determine the current " "page unless your view context provides a Request object " "in a #request method"
end
return false unless request.get? || request.head?
...
So even if your incorrect form is at exactly the same path as new_user_session_path, your logic won't match.
You may want to consider comparing controller.controller_name and controller.action_name directly instead. Not exactly elegant, but it's going to be more reliable.

How to change the response format depending on the data sent?

I'm doing some controllers to render reports and here is my problem:
The user open a page with a form which let it change the download format and the date of the report.
The download format is set trough a select input.
When the user press the button I want to response depending on the selected format.
The problem is that it's specified trough the url. So trying to do something like:
case format
when "xlsx" then format.xlsx{...}
when "html" then format.html{...}
...
end
doesn't work because rails or the browser (I'm not sure) expects an html response.
I've though of two options:
Change the url of the form onsubmit which makes the application more dependent on javascript. Or.
redirect_to url + ".#{params[:download_format]}"
The second way looks better to me but I need to pass the :report_date in the url and I can't find the way to do it.
I've tried this:
url = my_custom_url_path
redirect_to url + ".#{params[:download_format]}", :date_format => params[:date_format]
But it's not working.
In the form:
<%= f.select :download_format, { "xlsx" => "xlsx, "Online" => "html" } %>
In the controller:
def action
if download_format = params[:download_format].delete
redirect_to my_action_path(options.merge( :format => download_format ) ) and return
end
# do some logic here
respond_to do |format|
format.xlsx{...}
format.html{...}
end
end

Rails redirect_to with params

I want to pass parameters (a hash) to redirect_to, how to do this? For example:
hash = { :parm1 => "hi", :parm2 => "hi" }
and I want to redirect to page /hello
URL like this: /hello?parm1=hi&parm2=hi
If you don't have a named route for /hello then you'll have to hardcode the params into the string that you pass to redirect_to.
But if you had something like hello_path then you could use redirect_to hello_path(:param1 => 1, :param2 => 2)
Instead of:
redirect_to some_params
You can do:
redirect_to url_for(some_params)
You're turning the params into a url with url_for before passing it to redirect_to, so what you pass redirect_to ends up being a URL as a string, which redirect_to is happy to redirect to.
Note well: I don't understand why redirect_to refuses to use params. It used to be willing to use params. At some points someone added something to Rails to forbid it. It makes me suspect that there are security reasons for doing so, and if so, these security reasons could mean that manually doing redirect_to url_for(p) has security implications too. But I haven't yet been able to find any documentation explaining what's up here.
update: I've found the security warning, but haven't digested it yet: https://github.com/rails/rails/pull/16170
The easiest way (if it's not a named route) will be:
redirect_to "/hello?#{hash.to_param}"
See: http://apidock.com/rails/Hash/to_param
Simply, pass the hash into an argument in the URL, and in your code parse it to get out all needed values.
param_arr = []
hash.each do |key , val|
param_arr << "#{key}=#{val}"
end
params_str = param_arr.join("&")
redirect_to "http://somesite.com/somepage?#{params_str}"
I know this might be very basic way to do it, but hey, it'll get you somewhere :)

Rails Recaptcha plugin always returns false

I'm using the rails recaptcha plugin found here: http://github.com/ambethia/recaptcha/tree/master
I have signed up for an account on recaptcha.com, obtained a public & private key, and the site is configured with a global key (for now).
In config/environment.rb I setup the environment variables:
ENV['RECAPTCHA_PUBLIC_KEY'] = 'xxxxxxxxxxxxxxxx'
ENV['RECAPTCHA_PRIVATE_KEY'] = 'XXXXXXXXXXXXXXxx'
In my view I render the captcha like this:
<%= recaptcha_tags %>
And in my controller processing this form I have this:
unless verify_recaptcha # <-- always returns false
flash[:error] = "Your captcha entry was invalid"
render :action=>'new'
return
end
My problem is that verify_recaptcha always returns false.
I must be missing something simple, but I don't see it. And before I get a smart-alec reply, YES I'm typing the correct words into the captcha box :)
Just as a note, make sure you didn't accidentally switch around the public and private keys; they are different.
I can't tell if you're already handling the possibility that it is correct, in which case you would want to have something like this:
if verify_recaptcha
#thing.save!
redirect_to success_path
else
flash[:error] = "There was an error with the recaptcha code below. Please re-enter the code and click submit."
render :action => 'new'
end
And remember to use:
<%= recaptcha_tags :ssl => true %>
If you are using SSL.
I went in and looked at the recaptcha plugin. The pertinent part reads something like this:
recaptcha = Net::HTTP.post_form URI.parse("http://#{server}/verify"), {
"privatekey" => private_key,
"remoteip" => request.remote_ip,
"challenge" => challenge,
"response" => response
}
This takes the challenge and response and returns a response. When I tried it with a challenge and response I generated, I got "true\nsuccess". The following lines of code return false if:
answer, error = recaptcha.body.split.map { |s| s.chomp }
unless answer == "true"
Since I got back "true\nsuccess", answer will be "true", and the code should therefore pass.
Can you try sending the response directly using Net::HTTP and seeing what response you get?

Resources