Rails responds with status code 406 - ruby-on-rails

I have been working on a test for my function inside Ruby on Rails. However, the test (which expects a status code of :success) fails after receiving a status code 406. Here's the exact failure log:
Failure: Expected response to be a <:success>, but was <406>.
test_should_post_comment_through_token_successfully(CommentControllerTest)
test/functional/comment_controller_test.rb:271:in `block in <class:CommentControllerTest>'
I read a little about the 406 response, and found out that it stands of "Not Acceptable". so I tried setting the Accept, Content-Type, Accept-Language and Accept-Charset headers but I have had no luck.
Here's the code for my test:
test 'should post comment through token successfully' do
#params = {
id: 1,
body: "Test Comment",
username: "Bob"
}
#headers = {
"Accept" => "application/json",
"Accept-Language" => "en-US",
"Accept-Charset" => "utf-8",
"Content-Type" => "application/json",
"Token" => "abcdefg12345"
}
get :create_by_token, #params, #headers
assert_response :success
end
The create_by_token function inside the controller:
def create_by_token
#node = Node.find params[:id]
#user = User.find_by_username params[:username]
#body = params[:body]
#token = request.headers['Token']
p request.headers["Accept"]
p request.headers["Content-Type"]
p request.headers["Token"]
if #user && #user.token == #token
begin
#comment = create_comment(#node, #user, #body)
msg = {
status: :created,
message: "Created"
}
respond_to do |format|
format.xml { render xml: msg.to_xml }
format.json { render json: msg.to_json }
end
rescue CommentError
msg = {
status: :bad_request,
message: "Bad Request"
}
respond_to do |format|
format.xml { render xml: msg.to_xml }
format.json { render json: msg.to_json }
end
end
else
msg = {
status: :unauthorized,
message: "Unauthorized"
}
respond_to do |format|
format.xml { render xml: msg.to_xml }
format.json { render json: msg.to_json }
end
end
end
My route:
post '/bot/comment.:format', to: 'comment#create_by_token'
Am I missing something crucial? How do I go about solving this issue?
I would be happy to provide any other information you would need.

Seems this might be an error with respond_to do block. Kindly check with the routes whether you have configured as resources or resource.
Do update to resources than singular which will help with respond_to do block.
You can also try update your routes as/;
resources :samples, defaults: {format: :json}

Oh, stupid me. I realized that among all the params I was passing, the format was also being passed inside the URL. However, as in the test I was not mentioning a URL which I could pass in the format as the suffix (.xml or .json), I would have to mention the format inside the params explicitly. Here's the updated test code:
test 'should post comment through token successfully' do
#params = {
id: 1,
body: "Test Comment",
username: "Bob",
format: 'json'
}
#headers = {
"token" => "abcdefg12345"
}
post :create_by_token, #params, #headers
assert_response :success
end
Kudos #Sowmiya for leading me to this conclusion. Your answer was not exactly the solution I needed, but it provoked me to think.

Related

Sending back custom JSON response with ajax request

I'm trying to send back user information from the backend to the frontend but I'm having a hard time understanding how this is supposed to be formatted.
CONTROLLLER
def create
user = User.new(user_params)
if user.save
auth_token = Knock::AuthToken.new(payload: { sub: user.id })
created_user = {
userEmail: user.email,
userID: user.id
}
respond_to do |format|
format.json { render json: auth_token, created_user }
end
else
respond_to do |format|
format.json { render json: { errors: user.errors.full_messages }, status: :unprocessable_entity }
end
end
end
The problem is in the success path. It's giving me this error when I try to run my test.
ERROR:
SyntaxError:
/Users/Desktop/Work/ping-party/app/controllers/api/v1/users_controller.rb:23: syntax error, unexpected '}', expecting =>
/Users/Desktop/Work/ping-party/app/controllers/api/v1/users_controller.rb:29: syntax error, unexpected keyword_end, expecting '}'
/Users/Desktop/Work/ping-party/app/controllers/api/v1/users_controller.rb:37: syntax error, unexpected keyword_end, expecting '}'
TEST:
context "POST /v1/users" do
it "create a new user" do
post '/api/v1/users',
params: {
user: {
email: "test#idea.com",
password: "password123"
}
}
res = JSON.parse(response.body)
binding.pry
expect(res).to include("jwt")
expect(res).to include("user")
expect(User.count).to eq(1)
end
end
It says there is a syntax error but for the life of me I can't see what I'm doing wrong. Can anyone help? Thank You.
The problem is here:
render json: auth_token, created_user
The syntax is incorrect. Probably (according to your tests) you want something like:
render json: { user: created_user, jwt: auth_token.token)
More info.
You can store auth_token and created_user in a hash:
auth_token = Knock::AuthToken.new(payload: { sub: user.id })
created_user = {
userEmail: user.email,
userID: user.id
}
output = { auth_token: auth_token, created_user: created_user }
...
format.json { render json: output }
Then rails can render output like json.

Not able to call a controller action in Rspec

I have been trying to implement an RSpec for a Controller called "Estimate controller" to test whether my mailing functionality (sending estimate) working properly or not. But I'm not able to call the controller action from my RSpec. I need to set some values (to, subject, message, cc, current_user, attachments) in a hash and send that hash to Estimate controller.Here is what I tried..
estimates_controller_spec.rb
describe "post 'send_estimate'" do
it "should send estimate " do
#estimate = Fabricate(:estimate, id: Faker::Number.number(10), validity: "12/12/2014", total_value: 1222.00, user_id:#user.id, project_id: #project_id)
est_params = {
to: "rspec#rails.com",
subject: "Estimate",
message: "Check out the Estiamte details",
cc: "respec#rails.com",
current_user: #user,
attachments: ""
}
expect{
post :send_estimate, estimate: est_params
}.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
estimates_controller.rb
def send_estimate
respond_to do |format|
if #estimate.send_email(params[:to], params[:subject], params[:message], params[:cc], current_user, params[:attachments])
#estimate.create_activity :send_estimate, owner: current_user, recipient: #estimate.project
format.html { redirect_to lead_path(#estimate.project), notice: "Email sent Successfully"}
format.json { head :no_content, status: :ok}
else
format.json { render json: #estimate.errors }
format.html { redirect_to contacts_path, notice: 'Something went wrong' }
end
end
end

Rails, ActionController::UnknownFormat when testing a post (create) request

I am testing my rails application and so far this test is failing all the others pass.
The test is as follows:
test "should create broadcast" do
assert_difference('Broadcast.count') do
post :create, broadcast: { title: "title", content: "content", user_id: #broadcast.user_id}
end
assert_redirected_to broadcast_path(assigns(:broadcast))
end
and the controller has this snippet:
feed_result = []
if params.has_key?(:feeds)
feed_result = params[:feeds]
else
feed_result = ["None"]
end
if #broadcast.save
# Only after saving do we try and do the real broadcast. Could have been
# done using an observer, but I wanted this to be more explicit
results = BroadcastService.broadcast(#broadcast, feed_result)
if results.length > 0
# Something went wrong when trying to broadcast to one or more of the
# feeds.
#broadcast.errors[:base] << ("#{I18n.t('broadcasts.unable-message')}: #{results.inspect}")
flash[:error] = I18n.t('broadcasts.saved-but-message')
else
flash[:notice] = I18n.t('broadcasts.saved-message')
no_errors = true
end
if no_errors
format.html { redirect_to(broadcasts_url(page: #current_page)) }
format.json { render json: #broadcast, status: :created, location: #broadcast }
else
format.html { render :new }
format.xml {
# Either say it partly worked but send back the errors or else send
# back complete failure indicator (couldn't even save)
if results
render json: #broadcast.errors, status: :created, location: #broadcast
else
render json: #broadcast.errors, status: :unprocessable_entity
end
}
end
end
end
I have left out information that is unnecessary. it must be noted that if i am not running a test, and i am in fact running the live server this create method functions as expected and no error is thrown.
i have tried the following:
post :create, broadcast: { title: "title", content: "content", user_id: #broadcast.user_id, format: :html}
post :create, broadcast: { title: "title", content: "content", user_id: #broadcast.user_id, format: :json}
post :create, broadcast: { title: "title", content: "content", user_id: #broadcast.user_id, format: 'html'}
post :create, broadcast: { title: "title", content: "content", user_id: #broadcast.user_id, format: 'json'}
And the error persists.
If anyone has any ideas, id love to hear them!
Thanks,
Chris.

How should I format a JSON POST request to my rails app?

My Rails app has a player class that works perfectly. Players can be created, deleted, and updated from my rails control panel without any issues.
I would like a remote counterpart to be able to join in the fun by creating players using a JSON request. Following the advice of the auto generated Rails comments above my create method : # POST /players.json I have started sending requests to localhost:3000/players.json
The JSON
{
"player": {
"name": "test",
"room_id": 0,
"skin_id": 1,
"head_id": 2,
"torso_id": 3,
"legs_id": 4,
"x_position": 5,
"y_position": 6,
"direction": 7,
"action": "",
"gender": "f"
}
}
However, I am running into this error message:
ActionController::ParameterMissing in PlayersController#create
param not found: player
So I guess my question is: How should I structure the JSON I am sending?
Additional info:
Ruby Version: 2.0
Rails Version: 4.0
I have tried sending my requests using Postman
Update - Player Params
Here is the player params method from my controller (as requested):
def player_params
params.require(:player).permit(:name, :room_id, :skin_id, :head_id, :torso_id, :legs_id, :x_position, :y_position, :direction, :action, :gender)
end
Update 2 - Player controller
class PlayersController < ApplicationController
before_action :set_player, only: [:show, :edit, :update, :destroy]
skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }
# GET /players
# GET /players.json
def index
#players = Player.all
end
# GET /players/1
# GET /players/1.json
def show
end
# GET /players/new
def new
#player = Player.new
end
# GET /players/1/edit
def edit
#rooms = Room.all.map { |room| [room.name, room.id] }
end
# POST /players
# POST /players.json
def create
#player = Player.new(player_params)
respond_to do |format|
if #player.save
format.html { redirect_to #player, notice: 'Player was successfully created.' }
format.json { render action: 'show', status: :created, location: #player }
else
format.html { render action: 'new' }
format.json { render json: #player.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /players/1
# PATCH/PUT /players/1.json
def update
respond_to do |format|
if #player.update(player_params)
format.html { redirect_to #player, notice: 'Player was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #player.errors, status: :unprocessable_entity }
end
end
end
# DELETE /players/1
# DELETE /players/1.json
def destroy
#player.destroy
respond_to do |format|
format.html { redirect_to players_url }
format.json { head :no_content }
end
end
def manage_furni
#player = Player.find(params[:id])
#furni = Furni.all
end
def add_furni
player = Player.find(params[:id])
player.furnis << Furni.find(params[:furni])
redirect_to manage_furni_path(player)
end
def remove_furni
player = Player.find(params[:id])
item = InventoryItem.find(params[:item])
player.inventory_items.delete(item)
redirect_to manage_furni_path(player)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_player
#player = Player.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def player_params
params.require(:player).permit(:name, :room_id, :skin_id, :head_id, :torso_id, :legs_id, :x_position, :y_position, :direction, :action, :gender)
end
end
Update 3: logs
(
"Processing by PlayersController#create as JSON",
"Completed 400 Bad Request in 31ms",
"ActionController::ParameterMissing (param not found: player):",
"app/controllers/players_controller.rb:103:in `player_params'",
"app/controllers/players_controller.rb:40:in `create'",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.5ms)",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.9ms)",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (16.3ms)"
){
}
First of all, I think your data format is ok and is not the problem here. When I ran exactly into the same problem it was because I did not send the Content-Type: application/json header along with my request.
In Postman, you can select the 'raw' data format and then 'JSON (application/json)' to include this header. In my case it looks like this:
Alternatively, you can also try it with curl (source):
curl -X POST -H "Content-Type: application/json" -d '{"player": {"name": "test","room_id": 0,"skin_id": 1,"head_id": 2,"torso_id": 3,"legs_id": 4,"x_position": 5,"y_position": 6,"direction": 7,"action": "","gender": "f"}}' localhost:3000/players.json
If you omit the -H "Content-Type: application/json", then you will receive a 400 response with the "param not found" error, if you include it it should work.
If you are trying this:
via Postman - Under form-data tab, you need to have the vars as :
player[name]
player[room_id]
.
.
via jQuery:
$.ajax({ url: 'url', type: 'post', data: { player: { name: 'Test', room_id: '0' } } })

Test rails controller that respond in different formats

I have the following function in controller
def by_xy
#obj = BldPoly::find_by_xy(:x => params['x'], :y => params['y'])
respond_to do |format|
format.html { render :layout => false }
format.xml { render :layout => false }
format.json { render :layout => false }
end
and planning to write the automatic test in the following way
xml = nil
get :by_xy, {:x => 4831, :y => 3242, :format => :json}
assert_nothing_thrown { xml = REXML::Document.new(#response.body) }
td = REXML::XPath.first(xml, "//result/item")
assert_equal need_value, td.value
and I get
Completed in 50ms (View: 0, DB: 230) | 406 Not Acceptable [http://test.host/search/by_xy/4831/3242.json]
when I missed format in testing code - all works correctly,
how should I write the test?
I figured this out, actually; this is how it should be
get :by_xy, {:x => i[:x], :y => i[:y]}, :format => :json
For rails 5.1, when doing a post, I had to include the format attribute inside of my params hash
share_params = {
email: nil,
message: 'Default message.'
format: :json
}
post image_share_path(#image), params: share_params
assert_response :unprocessable_entity
If not I would get the error ActionController::UnknownFormat inside of my create controller
def create
#image = Image.new(image_params)
if #image.save
flash[:success] = 'Your image was saved successfully.'
redirect_to #image
else
respond_to do |format|
format.json do
render json: { #image.to_json },
status: :unprocessable_entity
end
end
end

Resources