How to find the request type? - ruby-on-rails

I want to use a conditional to run a statement based on the type of request, but there is no way I can reproduce the error in production to see what the request is, but I was thinking of doing it this way:
def save_path
if request.method == 'GET'
# don't save the timeout path or else the user has no obvious way to log in
session[:desired_path] = request.url unless request.url =~ /#{timeout_path}$/
end
end
So, basically I want to say if the request's method is a GET request then this line should run but don't know if my conditional is setup correctly or not. Any assistance on this will be greatly appreciated.

You can check using a built in method:
request.get?
This answer to a similar question may be helpful for further info:
https://stackoverflow.com/a/4023538/3435610

Related

How to use RSpec to test if one URL redirects to another URL?

I want to write a test that verifies that a URL is redirecting to a different one.
For example:
http://localhost:3000/news/foobar+baz/bar+boo
to
http://localhost:3000/news?tools=foobar+baz&sources=bar+boo
Using RSpec I can't seem to find a way to do this. Any suggestions?
In your case, you actually are trying to redirect from /foobar+baz/bar+boo to / with parameters appended. Potentially similar with this post: RSpec testing redirect to URL with GET params
Typically you shouldn't test the parameter with the redirect url syntax cus this is not the url location but the parameter. You can extract the location manually and parse the parameter to see if they are what you want. The first answer in that post gives an example.
You should make a request test. RSpec have:
expect(response).to redirect_to(...)
but it doesn't make assertions for the params
You use this one:
def expect_to_redirect_to_with_params(expected_url, expected_params)
redirect_url = response.location
uri = URI.parse(redirect_uri)
redirect_params = Rack::Utils.parse_query(uri.query)
expect(redirect_url).to eq(expected_uri)
expect(redirect_params).to eq(expected_params)
end
If you want you can make it to a custom matcher instead of method.

using # in rails routes..!

I am trying to have a routing rule which does the below
http://localhost:3003/tab/show#user11
when this url is loaded, the system should fetch the value after # and use it to generate user output.
I tried to add this rule in the routes.rb file
match "tab/show#:value => "tab#show"
but i could not able to use this and fetch the value after # like #current = request["value"]
Please suggest.
This part of url isn't being sent to the server during request. So, naturally, you can't get access to it on the server-side. Use javascript to access it.
And it's not Rails' "feature". It's common thing.
If you change your root to
match "tab/show/:value => "tab#show"
and use the URL
http://localhost:3003/tab/show/user11
then it will be available in the params hash:
#current = params[:value]
Unless you have a good reason for your current structure then this is the best way to do it.
Tom

How do I stub away send_file using mocha

The most direct attempt is to do
#controller.stubs(:send_file)
But that results in an output error like
ActionView::MissingTemplate: Missing template ...
So how do I stub away the send_file method from 2.3.x series.
The question is basically the same question that was asked on ruby-forum february 2009, which was never really answered.
Jarl
With Rails 4 (and maybe earlier)[1], the ImplicitRender handles this, and it checks against "performed?".
So, if you want to stub it out, stubbing the "performed?" should suffice:
subject.stubs(:performed?).returns(true)
subject.expects(:send_file).
with(image, disposition: "inline")
The implementation of performed is not that hard either:
performed?
response_body || (response && response.committed?)
end
So, in cases where you don't want, or cannot, stub performed simply ensure the response_body is not nil.
[1] With 5+ this has been moved into BasicImplicitRender.
Missing template errors probably points to the fact that send_file is now not doing anything (because of the stub) so Rails will try to go down the rendering chain and try to display the template.
You've effectively disabled the send_file call now, so you will need to change your stub to actually sends something Rails can interpret and think the request is handled because the file is served, in which case no template will need to be rendered anymore.
I've had to fight with this as well. As far as I can tell, the best solution for me has been:
(controller)
def some_action
send_file(some_action_filename)
end
private
def some_action_filename
"/public/something.tgz"
end
(test)
test "some_action" do
filename = Rails.root.join("tmp/testfile.tgz")
assert FileUtils.touch filename
#controller.expects(:some_action_filename).at_least_once().returns(filename)
post :some_action
end
I'm not a fan of altering your code to allow you to test, but I am less of a fan of spending hours and hours to find the right solution for a fairly trivial issue :)

How can I test the request object using a specific URL in application_helper_spec.rb?

I have a method defined in application_helper.rb that returns a canonical URL based on the current request. How can I mock or otherwise specify a complete URL for the controller?
# spec/helpers/application_helper_spec.rb
describe "#canonical_url" do
it "should return a path to an asset that includes the asset_host" do
# Given: "http://www.foo.com:80/asdf.asdf?asdf=asdf"
helper.canonical_url().should eq("http://www.foo.com/asdf.asdf")
end
end
# app/helpers/application_helper.rb
def canonical_url
"#{request.protocol}#{request.host}#{(request.port == 80) ? "" : request.port_string}#{request.path}"
end
EDIT:
Ultimately I want to test that canonical_url() returns the proper string for a bunch of different URLs, some with ports, some w/o, some with querystrings, some with paths, etc. Maybe that's overkill, but that is the end goal. I would like to both explicitly stub/mock/whatever the initial URL and then explicitly set the expectation in the matcher. I would love to be able to do this in one call, i.e. controller.request.url = 'http://www.foo.com:80/asdf.asdf?asdf=asdf' or request = ActionController::TestRequest.new :url => 'http://www.foo.com:80/asdf.asdf?asdf=asdf' but so far I have not found a single "hook" that allows me to do so. So that is the solution I'm looking for. How do I explicitly define the request URL for a given test.
I'd have done:
helper.request.stub(:protocol).and_return("http://")
helper.request.stub(:host).and_return("www.foo.com")
helper.request.stub(:port).and_return(80)
helper.request.stub(:port_string).and_return(":80")
helper.request.stub(:path).and_return("/asdf.asdf")
helper.canonical_url.should eq("http://www.foo.com/asdf.asdf")
The ultimate cause of this confusion lies in ActionPack:
ActionDispatch::TestRequest
ActionDispatch::Http::URL
e.g. if you set a port (ActionDispatch::TestRequest)
def port=(number)
#env['SERVER_PORT'] = number.to_i
end
e.g. then you read it (ActionDispatch::Http::URL)
def raw_host_with_port
if forwarded = env["HTTP_X_FORWARDED_HOST"]
forwarded.split(/,\s?/).last
else
env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
end
end
Setting SERVER_PORT will only take effect if you have no SERVER_NAME, HTTP_X_FORWARDED_HOST or HTTP_HOST already set.
My basic workaround for port settings was to add the port to the host - because request.port doesn't do what you want typically.
e.g. to set the port
request.host = 'example.com:1234'
The real answer is to read the code in ActionPack; it's fairly straightforward.
Very late to this party, but found it googling something similar.
How about:
allow_any_instance_of(ActionController::TestRequest).to receive(:host).and_return('www.fudge.com')
I appreciate allow_any_instance_of is sometimes frowned upon, but this does seem to get the job done.

Include params/request information in Rails logger?

I'm trying to get some more information into my Rails logs, specifically the requested URI or current params, if available (and I appreciate that they won't always be). However I just don't seem able to. Here's what I've done so far:
#config/environments/production.rb
config.logger = Logger.new(config.log_path)
config.log_level = :error
config.logger.level = Logger::ERROR
#config/environment.rb
class Logger
def format_message(level, time, progname, msg)
"**********************************************************************\n#{level} #{time.to_s(:db)} -- #{msg}\n"
end
end
So I can customize the message fine, yet I don't seem to be able to access the params/request variables here. Does anyone know if this is possible, and if so how? Or if there's a better way to get this information? (Perhaps even something Redis based?)
Thanks loads,
Dan
(Responding a long time after this was asked, but maybe it will help the next person.)
I just did something similar.
1) you need to override your logger separately from logging request-leve details. Looks like you've figured customizing your logger out. Answer is here:
Rails logger format string configuration
2) I log the request and response of all requests into my service. Note, that Rails puts a tonne of stuff into the headers, so just straight dumping the request or the headers is probably a bad idea. Also of note, my application is primarily accessed via an API. If yours is primarily a web-app, as I'm guessing most people's are, you probably don't want to inspect the response.body as it will contain your html.
class ApplicationController < ActionController::Base
around_filter :global_request_logging
...
def global_request_logging
http_request_header_keys = request.headers.keys.select{|header_name| header_name.match("^HTTP.*")}
http_request_headers = request.headers.select{|header_name, header_value| http_request_header_keys.index(header_name)}
logger.info "Received #{request.method.inspect} to #{request.url.inspect} from #{request.remote_ip.inspect}. Processing with headers #{http_request_headers.inspect} and params #{params.inspect}"
begin
yield
ensure
logger.info "Responding with #{response.status.inspect} => #{response.body.inspect}"
end
end
end
This should work! :) cheers.
logger.info({:user_agent =>
request.user_agent, :remote_ip =>
request.remote_ip}.inspect)
logger.info(params.inspect)
By the by.. This should be placed in your controllers action. Ex: If you place it in your create action it should also log the user_agent i.e the browser, remote_ip i.e the remote ip of the user and all the params.
you should look in the request class
like puts request.uri.
check here for more detail http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html

Resources