Sending back custom JSON response with ajax request - ruby-on-rails

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.

Related

RSPEC test of #update cannot update some parameters

I try testing my #UPDATE method in my Users Controller. The update of my fields (firstname, lastname, email, phone_number) works totally fine on my localhost but I can't make my test pass. Here is my code
I have this in my Users Controller :
def update
#user = User.find(params[:id])
authorize(#user)
#user.skip_reconfirmation! if #user.is_a_customer?
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_account_path, notice:
I18n.t('User_was_successfully_updated') }
format.json { render json: #user, status: :ok}
else
format.html { render :edit }
format.json { render json: #user.errors, status:
:unprocessable_entity }
end
end
and here is my RSPEC test :
RSpec.describe UsersController, type: :controller do
describe "PATCH update" do
let(:user) { create(:customer_user) }
before :each do
sign_in user
end
it "update the user information" do
allow(User).to receive(:find_by).and_return(user)
new_attributes = {
firstname: 'Roger',
lastname: 'Rabbit',
email: 'roger.rabbit#lapin.fr',
mobile_phone_number: '0606060606',
gender: 'female',
}
patch :update, params: { locale: I18n.locale,
id: user.id,
user: new_attributes
}
expect(user.firstname).to eq(new_attributes['firstname'])
expect(user.lastname).to eq(new_attributes['lastname'])
expect(user.email).to eq(new_attributes[:email])
expect(user.mobile_phone_number).to
eq(new_attributes[:mobile_phone_number])
end
Finally, here is the error message :
0) UsersController PATCH update user is a user update the user information
Failure/Error: expect(user.email).to eq(new_attributes[:email])
expected: "roger.rabbit#lapin.fr"
got: "customer#ecity.fr"
(compared using ==)
# ./spec/controllers/users_controller_spec.rb:29:in `block (4 levels) in <top (required)>'
Two more things :
- the test pass for firstname and lastname
- new_attributes['email'] and new_attributes['mobile_phone_number'] return nils ; that's why I symbolized key for the two last expectations
You need to reload the user object.
patch :update, ...
user.reload # ⇐ THIS
expect(user.firstname).to ...
Without reloading you have the stale object in your test and Rails has no ability to magically understand the object in the database has changed.

Rails responds with status code 406

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.

Rails render auth_token to API response header

I have custom JSON authentication API (without devise, etc). How do I render #user.authentication_token to response header instead of body?
in sessions_controller.rb
def create
if #user && #user.authenticate(params[:user][:password])
#user.sign_in_count += 1
#user.save!
render status: 200,
json: { success: true,
info: "Logged in sucessfully.",
data: { auth_token: #user.authentication_token } }
else
render status: :unprocessable_entity,
json: { success: false,
info: "Login failed." }
end
end
Try the response.header["auth_token"]
def create
if #user && #user.authenticate(params[:user][:password])
#user.sign_in_count += 1
#user.save!
render status: 200,
json: { success: true,
info: "Logged in sucessfully."}
response.headers["auth_token"] = #user.authentication_token
else
render status: :unprocessable_entity,
json: { success: false,
info: "Login failed." }
end
end
There is a headers object available in your controller action. So you can do the following:
headers['X-User-Token'] = #user.authentication_token

testing stripe with stripe.js in rails 3

My app uses the stripe.js java library to generate the stripe_card_token same as ryan bates did here.
I'm trying to add unit tests to my controller and I'm getting troubles in the generation of the token. I couldn't find the function to generate the token anywhere in the Stripe API, as it seems to be available only in the javascript.
How can I generate the stripe_token in the test?
Here's the part of the controller dealing with stripe:
def save_with_payment!
if valid?
customer = Stripe::Customer.create(
description: "#{user.email} - #{user.id} - #{billing_name}",
email: billing_email,
plan: plan,
card: stripe_card_token)
self.stripe_customer_token = customer.id
plan = validate_actual_plan customer.subscriptions.data[0].plan.id
save!
end
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card.
Your card wasn't charged. #{e.message}"
return false
end
Here's the controller:
def create
#subscription = Subscription.new(params[:subscription])
#subscription.user_id = current_user.id
#subscription.expiration_date = 1.month.from_now
#subscription.stripe_card_token = params[:subscription][:stripe_card_token]
respond_to do |format|
if #subscription.save_with_payment!
if current_user.upgrade_plan :premium
format.html { redirect_to user_trades_path(current_user), notice: 'Subscription was successfully created. Compliments you are now subscribed to the premium plan' }
format.json { render json: user_trades_path(current_user), status: :created, location: #subscription }
else
format.html { redirect_to home_pricing_path, notice: 'Error while upgrading your account, please contact us' }
format.json { render json: home_pricing_path, status: :created, location: #subscription }
end
else
format.html { render action: "new" }
format.json { render json: #subscription.errors, status: :unprocessable_entity }
end
end
end
This is the Coffeescript generating the token:
processCard: ->
card =
number: $(page.cardNumber).val()
cvc: $(page.cardCode).val()
expMonth: $(page.cardMonth).val()
expYear: $(page.cardYear).val()
Stripe.card.createToken(card, #handleStripeResponse)
Here's the test:
test "should create subscription" do
begin
StripeMock.start
card = {
number: "4242424242424242",
cvc: "123",
expMonth: 1.month.from_now.month,
expYear: 1.year.from_now.year,
}
token = Stripe.card.createToken(card)
assert_difference('Subscription.count') do
post :create, subscription: {
billing_email: #subscription.billing_email,
billing_city: #subscription.billing_city,
billing_country: #subscription.billing_country,
billing_name: #subscription.billing_name,
billing_street2: #subscription.billing_street2,
billing_street: #subscription.billing_street,
billing_zip: #subscription.billing_zip,
stripe_card_token: token,
plan: #subscription.plan }
end
assert_redirected_to subscription_path(assigns(:subscription))
ensure
StripeMock.stop
end
end
I figured that creating the token was indeed possible with the Stripe API, as described here:
https://stripe.com/docs/api#create_card_token
I had also found an issue with the plan I was going to subscribe, because I'm using StripeMock, there's no connection to the real/test stripe at all. this means that my mock doesn't know about the plans I try to subscribe.
I had to generate a little function to generate the plan as well.
here's its code:
def create_plan
plan = {
:amount => 1800,
:interval => 'month',
:name => 'premium',
:currency => 'gbp',
:id => 'premium'
}
response = Stripe::Plan.create plan
end

RSpec request example failing

I'm trying to do a really simple request spec for testing my API methods in my application. Right now I'm getting 302 message when I should be getting 200 with this test.
The spec:
require 'spec_helper'
describe UsersController do
describe "#create" do
it "creates a new user " do
post '/users', user: FactoryGirl.attributes_for(:user)
expect(response.status).to eq 200
end
end
end
The factory:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:username) { |n| "Person#{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
end
end
The controller method:
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
What am I missing?
So you need to make the asynchronous post request, it should be something like below,
it "creates a new user " do
xhr :post, '/users', user: FactoryGirl.attributes_for(:user)
expect(response.status).to eq 200
end
Try this, it might work
To solve the issue I need to add the ACCEPT header to my request, like so:
post "/users", { user: #user } , { accept: 'application/json' }
Doing this fixed the issue which was the server not interpreting the request as expecting json in return.

Resources