Raw POST from Ruby on Rails - ruby-on-rails

I'm trying to do a raw POST to an internal page from a unit test, and for some reason I'm getting the following error:
NoMethodError: undefined method `symbolize_keys' for #<String:0x258a910>
unit/call_route_attempt_test.rb:10:in `test_response_from_call_info'
My code looks like this:
post :call_info, '<?xml version="1.0" encoding="UTF-8"?><request-call-info>...SOME XML HERE...</request-call-info>'
That should be fine according to the API docs. The only format I can get to work is if I send it as parameters like so:
post :call_info, :post => {:a_var => '<?xml version="1.0" encoding="UTF-8"?><request-call-info>...SOME XML HERE...</request-call-info>'}
I have a feeling I need to require some part of the library that for some reason isn't working here.
Edit
As user Sarah Mei points out, I'm calling the wrong post method. I think it has to do with my class inheritance, which I'm not sure I can change given the circumstances of me running a test. The class definition is as follows:
class anApiControllerTest < ActionController::TestCase
The method I'm trying to implement is the post (ActiveResource::Connection) method listed on the Rails API docs. I'm really new to this, quite lost and on a deadline. Any help is greatly appreciated. Thanks!

It depends on which post method you're calling. There's one in ActionController::Integration::Session, one in ActionController::TestProcess, one in ActiveResource::Connection...etc. Most of them take a params hash as the second parameter, so if the second call works, you're probably not calling the post you think you're calling.

Related

Rails API and Strong PARAMS

I am trying to create an api to create record Foo using the rails-api gem.
I initially ran the generator command to tell rails to create a controller for me and it created this:
def create
#foo = Foo.new(foo_params)
#foo.save
respond_with(#foo)
end
And this (Strong params):
def foo_params
params.require(:foo).permit(:bar)
end
This is pretty standard stuff and will work when using form_for to submit data to the create method.
In my case, I'm creating a stand-alone API web service that will only interact via external API calls.
So the issue that I'm experiencing, is I don't know how to post the :bar param via API. I tried posting a :bar param, but this leads to a 'param is missing or the value is empty: foo' error. I understand why this is happening, but I have no idea how to get around this...
Is there a better way to do this or should I provide the api param in a different way?
PS. Currently my api POST call looks like this:
http://localhost:3000/api/v1/foo.json?bar=test#mail.com
you cannot use the ?+argument at the end of the url for a POST HTTP request, it's only for a GET request.
You must use the data component of the HTTP call, that is not embedded in the URL
therefore, you cannot just make this from your browser address bar and must use curl or a great tool as Postman (free on the chrome App Store)
and in this data field, you can include the object you want to post (postman gives you a neat key value interface to do so)
let me know if you need more details on the curl function for command line calls, but I recommend that you use a nice tool as Postman, so useful if you're not used to these calls
EDIT : this is the URL to get Postman : https://www.getpostman.com

How to Test an Instance Variable in Rspec

I am having trouble testing an external instance variable with Rspec. While there are some similar questions on StackOverflow, I haven't been able to find a solution for testing it in a GET request (since this is for an API).
I have an ApiController method that does something along these lines:
class ApiController < ApplicationController
...
def auth(token)
#user = User.find_by_token(token)
...
end
Then, I have a request spec that looks something like this:
describe 'GET /v1/friends' do
it 'returns friends' do
ApiController.any_instance.stub(:auth)
get "v1/friends"
...
end
end
I get an error that says undefined method XXX for nil:NilClass that stems from the fact that the #users instance variable isn't being passed into the GET request.
I have tried using assigns() and that doesn't seem to work, while not stubbing the auth class isn't an option for a different reason. And, simply setting the instance variable doesn't seem to work, because I've read that Rspec assumes that it's its own variable rather than one used in the test (?).
Is there any way to set the #user instance variable to a fake user when running the GET request?
Thanks in advance for any help!
I ended up refactoring quite a bit of other code to run the authentication method that creates the instance variable in the actual controller. I don't believe there is a way to set a variable in Rspec for use in a GET request.
When using an integration test to test authenticate_with_http_token, you'll need to include it like so in the GET request:
get '/v1/path-for-api', nil, authorize: 'Token token=#{user.token}'
From there, the variable was properly set now and I was able to test the requests.

Dynamic method call in routes spec

I am testing simple get requests for my routes using rspec in my Rails 3.2 application. Since all are get requests, and all just have different action names which are similar to the views' names, it would be really repetitive to manually write a different test for each get request.
Instead, I wanted to come up with something like this:
%(action_1 action_2 action_3 action_4).each do |action|
it "routes to the #{action} page" do
get("liver_diseases#{action}_path").should route_to("liver_diseases##{action}")
end
end
It fails at this pseudocode: get("liver_diseases_#{action}_path")
So what I need to do is a dynamic method call - but for what I have found out, that would involve .send(:method_name), for which I need to know the class name. And I couldn't find that.
What do I need to do for this method call to work?
that would involve .send(:method_name), for which I need to know the
class name
When the receiver is missing, it's always self. In the context of a controller example, self should be a controller instance. So you should be able to get that path with:
send "liver_diseases_#{action}_path"
which should be equivalent to:
controller.send "liver_diseases_#{action}_path"

Using rspec to test ActionMailer with should_receive

I have an RSpec test like this:
it "should ..." do
# mailer = mock
# mailer.should_receive(:deliver)
Mailer.should_receive(:notification_to_sender)#.and_return(mailer)
visit transactions_path
expect do
page.should_not have_css("table#transactions_list tbody tr")
find('#some_button').click
page.should have_css("table#transactions_list tbody tr", :count => 1)
end.to change{Transaction.count}.by(1)
end
If I remove the commented pieces at the top, the test passes. But with the commented sections in place (how I'd expect to write it) the test fails.
I got the commented pieces off some of googling around the net, but I don't really understand what it's doing or why this fixes it. It seems like there should be a cleaner way to test emails without this.
Can anyone shed some light? Thanks!
I'm using rails 3 and rspec-rails 2.10.1
I think you want an instance of Mailer to receive notification_to_sender not the class. From the Rails API
You never instantiate your mailer class. Rather, your delivery instance methods are automatically wrapped in class methods that start with the word deliver_ followed by the name of the mailer method that you would like to deliver. The signup_notification method defined above is delivered by invoking Notifier.deliver_signup_notification.
Therefore I would use
Mailer.any_instance.should_receive(:notification_to_sender)
Also, if you need to get the last delivered message, use
ActionMailer::Base.deliveries.last
I think that should solve your problem.
You're likely calling Mailer.notification_to_sender.deliver in your controller, or better yet, a background job. I'm guessing notification_to_sender probably takes a parameter as well.
Anyways, when you call the notification_to_sender method on Mailer you're getting back an instance of Mail::Message that has the deliver method on it. If you were simply doing Mailer.notification_to_sender without also calling deliver, you could run what you have there with the comments and all would be fine. I would guess you're also calling deliver though.
In that case your failure message would be something like
NoMethodError:
undefined method `deliver' for nil:NilClass
That is because nil is Ruby's default return value much of the time, which Rails also inherits. Without specifying the mailer = mock and .and_return(mailer) parts, when the controller executes in context of the test then notification_to_sender will return nil and the controller will try to call deliver on that nil object.
The solution you have commented out is to mock out notification_to_sender's return value (normally Mail::Message) and then expect that deliver method to be called on it.

Testing GET in a rails controller

I have a feeling I'm just doing something wrong syntactically but it's surprisingly difficult to Google "GET" so I was hoping someone here might know the answer to this.
I'm trying to test a Rails controller from an RSpec test. I'm following an example I found here - http://www.elevatedrails.com/articles/2007/09/10/testing-controllers-with-rspec/ but I'm stuck on the actual execution of the method I'm testing.
I'm doing a GET request where as the post above does a POST. I'm passing in 2 parameters manufacturer and model.
My URL will ideally look something like http://mysite.com/Products/index/Manufacturer/ModelName
I can't figure out the syntax for the get request call in the rest. Right now I have
get :index, :manufacturer=>#manufacturer, :modelName=>#modelName
and I get back
ArgumentError in 'ProductController Find a valid product should retrieve the product'
wrong number of arguments (0 for 2)
Any thoughts?
edit: It should be noted #manufacturer and #modelName are defined in before(:each)
As i suspected this was me being green to rails programming.
I was defining the controller method as
def index(manufacturer, modelName)
When really i needed to use the params hash to access the attributes. I then had to define a custom route as id is the only parameter expected to be passed into a controller method by default.
once i did that i changed the spec to read
get :index, {:manufacturer=>#manufacturer, :modelName=>#modelName}
and it worked.
Thanks for the comments everyone.

Resources