I'm stuck with a small issue which I can't seem to find on the RSpec Doc (or elsewhere). I suspect it's probably to do because it's trying an HTTP call but unsure.
I'm currently attempting to mock a response in my controller, the actual response is coming straight from aws-sdk (so it's an external service).
Controller:
response = {
snapshot_id: client.copy_snapshot({foo, bar}).snapshot_id
}
Is it possible to stub .snapshot_id?
_spec.rb
before do
allow(client).to receive(:copy_snapshot).and_return('Something')
put :update, format: :json
puts JSON.parse(response.body)
end
The tests passes successfully without adding .snapshot_id on the controller page and I can see
{"snapshot_id"=>"Something"}
Otherwise I get "this resource is currently unavailable." adding it in, I'm slightly lost if I'm doing it wrong or if this is intended behavior.
The reasoning is that when the server is on I will actually get a response back, however omitting snapshot_id causes the server to hang as amazon returns back a lot of data (headers, etc)
Any help is greatly appreciated.
Related
I'm attempting to stub a request to a Controller using WebMock. However, as I'm creating the stub, the request isn't being intercepted the way I'd expect or want it to be.
The Controller does nothing but render JSON based on the query parameter:
def index
render json: MyThing.search(params[:query]).as_json(only: [:id], methods: [:name_with_path])
end
And the stubbing goes as follows:
mything_val = { ...json values... }
stub_request(:any, mything_path).with(query: { "query" => "a+thing" }).to_return(body: mything_val, status: 200)
page.find('.MyThingInput > input').set('a thing')
# Note: I've tried this with and without the `query:` parameter, as well as
with and without specifying header info.
This is triggering a React component. What it does is, when a word or words are entered into the input, it sends an AJAX request to mything_path with the inputted value, which returns as JSON several suggestions as to what the user might mean. These are in a li element within .MyThingInput-wrapper.
In the spec file, I include:
require 'support/feature_helper'
require 'support/feature_matchers'
require 'webmock/rspec'
WebMock.disable_net_connect!
What's actually happening when I input the text into the React component however is that regardless of the WebMock stub, it's hitting the Controller, making the DB request, and failing due to some restrictions of the testing environment. My understanding of how this should work is that when the request is made to mything_url, it should be intercepted by WebMock which would return the values I pre-defined, and never hit the Controller at all.
My guess is that somehow I'm mocking the wrong URI, but honestly, at this point I'm really uncertain. Any and all input is appreciated, and I'm happy to clarify any points I've made here. Thanks massively!
What ended up solving my problem was stubbing out the model. I'd tried stubbing the Controller but ran into issues; however, this code did the trick:
before do
mything_value = [{ "id" => "fb6135d12-e5d7-4e3r-b1h6-9bhirz48616", "name_with_path" => "New York|USA" }]
allow(MyThing).to receive(:search).and_return(mything_value.to_json)
end
This way, it still hits the controller but stubs out the DB query, which was the real problem because it made use of Elasticsearch (not running in test mode.)
I'm not super happy about hard-coding the JSON like that, but I've tried a few other methods without success. Honestly, at this point I'm just going with what works.
Interestingly enough, I'd tried this method before Infused's suggestion, but couldn't quite get the syntax right; same went with stubbing out the Controller action. Went to bed, woke up, tried it again with what I thought was the same syntax, and it worked. I'm just going to slowly back away and thank the code gods.
If elastic search is the problem, then maybe try
installing Webmock
# in your gemfile
group :test do
gem 'webmock'
end
stubbing out the requests to elasticsearch and returning the JSON
Something like this in spec_helper:
config.before(:each) do
WebMock.enable!
WebMock.stub_request(:get, /#{ELASTICSEARCH_URL}/).to_return(body: File.read('spec/fixtures/elasticsearch/search-res.json'))ELASTICSEARCH_URL
# and presumably, if you are using elasticsearch-rails, you'd want to stub out the updating as well:
WebMock.stub_request(:post, /#{ELASTICSEARCH_URL}/).to_return(status: "200")
WebMock.stub_request(:put, /#{ELASTICSEARCH_URL}/).to_return(status: "200")
WebMock.stub_request(:delete, /#{ELASTICSEARCH_URL}/).to_return(status: "200")
end
Of course, this stubs out all calls to elastic-search and returns the same JSON for all answers. Dig into the documentation for webmock if you need a different response for each query.
I'm building a RESTful API using Rails 3.2.21. The API should only response to xml or json for now. I have a simple resource called Users with a create action, that creates a new user on a POST Request.
Here is the Code for doing that:
respond_to :json, :xml
def create
#user = User.new(params[:user])
#user.save
respond_with(#user)
end
Everything goes fine so far, but then I tried to check the error cases. So if I do a POST request to /users.html, the answer is '406 Not Acceptable'. What is correct. But then I saw in the database, that the user was created anyway. So the create action is executed although the requested accept format (html) is not supported and a 406 error is responded.
I don't know if this is intended. Until now I really liked response_with from Rails, because it does lots of stuff for me, but this behaviour seems to be odd. From the perspective of a client you try to create a new user, receive 406 and you obviously assume that the request failed, so the user is not created, right?
Since I've defined the accepted MIME types in the class method respond_to, it should be possible for Rails, to prevent execution of the entire action. Sure, respond_to is only related to the http response, but then for the client it is still unknown which part of the POST request succeeded and which failed.
Are there any setting or additional functions in Rails what I've overseen or is this just 'not thought to the end' in case of POST requests using respond_with or is this behaviour even intended to react like that? Of course I can add some custom before_filters for checking the MIME types, but then I can also remove respond_with and handle everything on my own.
I'm looking for a nice and clean solution for that problem using respond_with.
I have an API centric application (/api/v1/users) it simply return all users restfully with JSON format.
My problem is, if I call that route on the controller, it returns "Timeout::Error"
What is the problem?
class BaseController < ApplicationController
def index
return HTTParty.get('http://localhost:3000/api/v1/users').body
end
end
Update
users_controller.rb (/api/v1/users)
application_controller.rb
https://gist.github.com/4359591
Logs
http://pastie.org/5565618
If I understand correctly, you have an API end-point, at /api/v1/users, and your BaseController#index is calling that method?
If that is correct, inside the same rails process, and you are testing in development mode (as I can tell from your url), then you only have a single process running, which can only handle a single request at once. So if you start a request to BaseController#index, it will start another request to your own test-server, which is busy, and it will just wait until it times out.
If you want to test your API, I would look at a client tool like e.g. Postman.
HTH.
Originally I had quite usual ajax form with json response:
def create
# created logic omitted as most likely irrelevant
render :json => {:success => true} #over simplified JSON for debug purposes
end
So far so good, works as expected. I've added security on the create action via ssl_requirement gem:
class RegistrationsController < Devise::RegistrationsController
ssl_required :create
# rest of the code omitted, 'create' action as above
end
All of a sudden I get the following in my form response (observing in HttpFox):
Error loading content (NS_ERROR_DOCUMENT_NOT_CACHED)
The create action runs as expected (enforces HTTPS, creates an object but... fails in the browser. To be specific, fails in Firefox (works on chrome). Any clues and ideas will be greatly appreciated.
Regards,
I'm not certain, but I believe your problem has to do with cross-site AJAX requests.
The fact that you are using a different protocol is making firefox believe you are making a cross-site request. Chrome, I believe, is less strict with this restriction when on local. Try visiting the site itself over https and see if the AJAX request goes through.
Rails 3 currently routes a HEAD request to the matching GET route. There is a head? method on the request, but in returns false and the request acts like a get request. Can I detect if the request is a HEAD request?
Reasoning: I get that a HEAD request should return the EXACT same headers as the get, so Rails wants to perform the full GET and then shave off the body. However, I can conform to this request without issuing the same DB calls, etc that the GET would. Does this make sense?
I had this exact issue. It turns out that enabling caching causes this. Turn caching off in your environment and #head? will work as expected.
The issue is that Rack::Cache turns HEAD requests into GET requests so they can be cached. This is arguably the correct behavior, but it interfered with my application.
You can use the request.head? method to find out if it's a HEAD request:
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-head-3F
Once you've determined that it is, you can also use the controller's head() method instead of the typical render:
http://guides.rubyonrails.org/layouts_and_rendering.html#using-head-to-build-header-only-responses
So I'd simply check request.head? before bothering with the database activities. Then use
head :ok, :custom_header => 'value'
def index
if request.head?
head :created
else
Rails.logger.info "Derp #{request.method}"
end
end
Hmm. The above controller method works like I'd expect on Ruby v1.9.3-p194 and Rails v3.2.3; 201's w/o response body for the HEAD requests and 200's w/ for the GET's.