Ruby JSON API and post request with Postman - ruby-on-rails

I'm using postman to make post request to my rails/grape API
Here is the json object
{
"customer":{
"first_name":"Joe",
"last_name":"Doe",
"email":"test#test.com",
"phone":"999-999-9999",
"addresses_attributes":[{
"address":{
"address1":"123 somewhere st",
"customer_id":"",
"address2":"",
"city":"Moldor",
"state":"CA",
"zip":"99999",
"region_id":"1"
}
}]
}
}
If send this to a api/v1/customers.json
I get the following error message
"error": "first_name is missing, last_name is missing, email is missing, phone is missing",
If I change the JSON format to:
{
"first_name":"Joe",
"last_name":"Doe",
"email":"test#test.com",
"phone":"999-999-9999",
"addresses_attributes":[{
"address":{
"address1":"123 somewhere st",
"customer_id":"",
"address2":"",
"city":"Moldor",
"state":"CA",
"zip":"99999",
"region_id":"1"
}
}]
}
I does creates the customer but it does not creates the address
In my Models I have
#customer.br
has_many :addresses
accepts_nested_attributes_for :addresses, allow_destroy: true
#address.rb
belongs_to :customer
Here is the api/vi/curtomer.rb
desc "Create a Customer"
params do
requires :first_name, type: String, desc: "First Name"
requires :last_name, type: String, desc: "Last Name"
requires :email, type: String, desc: "Email"
requires :phone, type: String, desc: "Phone"
optional :notes, type: String, desc: "Notes"
end
post do
# Tried with new instead of create
# test = Customer.new({
# first_name: params[:first_name],
# last_name: params[:last_name],
# email: params[:email],
# phone: params[:phone],
# notes: params[:notes],
# addresses_attributes: params[:addresses]
# })
Customer.create({
first_name: params[:first_name],
last_name: params[:last_name],
email: params[:email],
phone: params[:phone],
notes: params[:notes]
# addresses_attributes: params[:addresses]
})
end
The address looks pretty much the same as the customers
I'm not using controllers per Grapes Documentation
EDIT: to add customer.rb create code

Think your json data should be:
{ "customer":
{
"first_name":"Joe",
"last_name":"Doe",
"email":"test#test.com",
"phone":"999-999-9999",
"addresses_attributes":[{
"address1":"123 somewhere st",
"customer_id":"",
"address2":"",
"city":"Moldor",
"state":"CA",
"zip":"99999",
"region_id":"1"
}]
}
}
Refer to this example.
If it not works, show your controller code.

Related

Ruby on Rails - Failed to create new user: Validation failed

On creating a new user using postman, I'm getting the following error:
Failed to create new user: Validation failed: First name can't be blank, Email can't be blank, Email is invalid; Params: {:email=>nil, :first_name=>nil, :last_name=>nil, :plan=>"Basic", :role=>"requester_readonly", :phone_number=>nil, :ip=>nil, :company_name=>nil, :product_id=>2, :user_reference_id=>nil, :handle=>nil}
Error on postman:
{
"error": [
"First name can't be blank",
"Email can't be blank",
"Email is invalid"
],
"status": 400
}
I am passing the following values to params in postman:
{
"email": "customer#yahoo.com",
"firstName": "Demo",
"lastName": "Customer",
"password": "Password_0",
"phoneNumber": "0123456789",
"ip": "10.10.2.125",
"company": "xyz"
}
This is the function for user registration:
def register
product_id = $product_id
if params[:plan]
#plan = AppCommon::Plan.where(name: params[:plan], product_id: product_id).first
end
#plan = #plan || AppCommon::Plan.find_default(product_id)
form_params = {email: params[:email], first_name: params[:firstName], last_name: params[:lastName], password: params[:password], plan: #plan.name, role: 'requester_readonly', phone_number: params[:phoneNumber], ip: params[:ip], company_name: params[:company], product_id: product_id, user_reference_id: params[:referenceId]}
service = Web::UserCreater.new(form_params)
result = service.perform
#user = service.user
if result.success?
render json: {status: 200, authentication_token: #user.authentication_token}
else
error_response(#user.errors.full_messages.to_a)
end
end
probably the ruby on rails controllers are wrapping the params under a name https://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html
you can either turn it off by setting wrap_parameters false on the top of your controller but I do not advise on this!
you could probably print/log the entire params to see how they look like and probably permit them
pull form_params into its own method require the param wrapper then permit what you need
def form_params
params.require(:user).permit(:email, :first_name, :last_name, :password, :phone_number, :ip, :company_name, :user_reference_id)
end
then in your method get these params then merge the defaults:
user_creater_attributes = form_params.merge(product_id: product_id, plan: #plan.name, role: 'requester_readonly')

How to seed image file in nested attributes Rails

I got this error when trying to seed database with image file in nested attributes.
rails aborted!
ArgumentError: wrong number of arguments (given 1, expected 0; required keywords: io, filename)
product.rb
class Product < ApplicationRecord
belongs_to :user
has_many :founders, dependent: :destroy
accepts_nested_attributes_for :founders, allow_destroy: true
founder.rb
class Founder < ApplicationRecord
belongs_to :product, optional: true
has_one_attached :profile_picture
end
seed.rb
user = User.create!(email: 'user#example.com', password: '1234567890')
10.times do |index|
#product = Product.create(
user: user,
name: "Product #{index+1}",
tagline: Faker::Lorem.sentence,
industry: Faker::Company.industry,
website: Faker::Internet.url,
company_name: Faker::Company.name,
company_website: Faker::Internet.url,
founders_attributes: [
{
name: Faker::Name.name,
email: Faker::Internet.email,
website: Faker::Internet.url,
profile_picture: { io: File.open(Rails.root + "app/assets/images/profile_picture.png"), filename: 'profile_picture.png', content_type: 'image/png' }
},
{
name: Faker::Name.name,
email: Faker::Internet.email,
website: Faker::Internet.url,
profile_picture: { io: File.open(Rails.root + "app/assets/images/profile_picture.png"), filename: 'profile_picture.png', content_type: 'image/png' }
}
]
)
end
I have no idea to solve this error.
Give me some advice please.
You can do it without nested attributes. And by the way you didn't close your files:
PNG_PATH = Rails.root.join('app', 'assets', 'images', 'profile_picture.png')
user = User.create!(email: 'user#example.com', password: '1234567890')
1.upto(10) do |index|
#product = Product.create(
user: user,
name: "Product #{index}",
tagline: Faker::Lorem.sentence,
industry: Faker::Company.industry,
website: Faker::Internet.url,
company_name: Faker::Company.name,
company_website: Faker::Internet.url
)
2.times do
founder =
#product.founders.create(
name: Faker::Name.name,
email: Faker::Internet.email,
website: Faker::Internet.url
)
File.open(PNG_PATH) do |file|
founder.profile_picture.attach(io: file, filename: File.basename(file.to_path))
end
end
end

Test error message when validating model with rspec

I've inherited a rails api and I'm trying to test controllers. I have an endpoint '/api/v1/vitcords' where I create new vitcords. The video model only has a validation name. So my doubt is how to test that when I create a new video without specify a name, I get the message error I want, that in this case is "Vitcord name has to be specified". Thanks.
This is the Vcord model
class Vcord
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Spacial::Document
include Concerns::Vitcord::M3u8
include Concerns::Vitcord::User
# Validations
validates_presence_of :name
# Atributes
field :name, type: String
field :location, type: Array, spacial: true
field :address, type: String
field :closed, type: Boolean, default: false
field :public, type: Boolean, default: false
field :thumb, type: String
end
This is the controller video_controller.rb
module Api::V1
class VitcordsController < ApiController
def create
user = current_resource_owner
# Validation
param! :name, String, required: true
param! :location, Hash, required: false
param! :address, String, required: false
ap params[:location]
ap params[:location][:latitude]
ap params[:location][:longitude]
# Creating
vcord = Vcord.new()
vcord.name = params[:name] if params[:name]
if params[:location] && params[:location]['latitude'] && params[:location]['longitude']
vcord.location = {
lng: params[:location]['longitude'],
lat: params[:location]['latitude']
}
end
vcord.address = params[:address] if params[:address]
vcord.creator = user
if vcord.save
vcord.members.each do |member|
Notification.generate_notification_for_vitcord_invited(vcord, member)
end
#vitcord = vcord
else
error(:internal_server_error, ["Vitcord name has to be specified"], nil)
end
end
end
And this is the spec
require 'rails_helper'
describe "POST /api/v1/vitcords" do
before(:each) do
db_drop
post "/oauth/token", {
:grant_type => 'assertion',
:assertion => TOKEN
}
#token = response_json['access_token']
end
it "sends an error if a vitcord is created with name nil" do
header 'Authorization', "Bearer #{#token}"
post '/api/v1/vitcords', {
address: "Calle Rue del Percebe",
location: {
latitude: 40.7127837,
longitude: -74.00594130000002
}
}
//This does not work but it would be something like this
expect(error).to eq("Name has to be specified")
end
end
Well, you should refactor your code, but answering your question, you can add an error to you object by doing (look that I used #vcord and not vcord):
#vcord.errors.add(:name, 'Vitcord name has to be specified')
(as you can see here http://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-add)
and on your test:
expect(assigns(:vcord).errors.name).to eq('Vitcord name has to be specified').

Using Grape to build a Rails API but having issues posting JSON

Here is my API post:
resource :service_requests do
get do
authenticate!
current_company.service_requests
end
params do
requires :service_request, type: Hash do
optional :prefix, type: String
requires :first_name, type: String
requires :last_name, type: String
requires :contact_email, type: String, regexp: User::EMAIL_REGEX
requires :telephone, type: String
end
end
post do
authenticate!
{ service_request: params[:service_request] }
end
end
Here is what my json post looks like:
{
'service_request': {
'first_name': 'Foo',
'last_name': 'Bar',
'contact_email': 'foo#bar.com',
'telephone': '111-111-1111'
}
}
The error I am receiving is:
ActionDispatch::ParamsParser::ParseError (795: unexpected token at '{
'service_request': {
'first_name': 'Foo',
'last_name': 'Bar',
'contact_email': 'foo#bar.com',
'telephone': '111-111-1111'
}
}'):
Not sure what I am doing wrong. Anyone see anything that stands out?
Use double quotes in your json:
{
"service_request": {
"first_name": "Foo",
"last_name": "Bar",
"contact_email": "foo#bar.com",
"telephone": "111-111-1111"
}
}

Grape API in Rails and issues with Strong Parameters

Here is what my API looks like
resource :service_requests do
before do
error!('Unauthorized. Invalid token', 401) unless current_company
end
get do
current_company.service_requests
end
params do
requires :service_request, type: Hash do
optional :prefix, type: String
requires :first_name, type: String
requires :last_name, type: String
requires :contact_email, type: String, regexp: User::EMAIL_REGEX
requires :phone_number, type: String
requires :address, type: String
optional :address2, type: String
requires :city, type: String
requires :state, type: String
requires :zip_code, type: String
requires :country, type: String
requires :address_type, type: String
requires :troubleshooting_reference, type: String
requires :line_items, type: Array do
requires :type, type: String
requires :model_number, type: String
requires :serial_number, type: String
optional :additional_information, type: String
end
end
end
post do
parameters = ActionController::Parameters.new(params).require(:service_request)
sr = ServiceRequest.new(
parameters.permit(
:troubleshooting_reference,
:rma,
:additional_information
)
)
sr.build_customer(
parameters.permit(
:prefix,
:first_name,
:last_name,
:contact_email,
:phone_number
)
)
#
# shipping_info = customer.build_shipping_information(
# parameters.permit(
# :address,
# :address2,
# :company_name,
# :city,
# :state,
# :zip_code,
# :country,
# :address_type
# )
# )
if sr.save
sr
else
sr.errors.full_messages
end
end
end
The problem I am running into is that when the save method is called, I am getting this error Unpermitted parameters: first_name, last_name, contact_email, phone_number, address, city, state, zip_code, country, address_type, line_items
Here is what my JSON post looks like:
{
"service_request": {
"first_name": "Foo",
"last_name": "Bar",
"contact_email": "foo#bar.com",
"phone_number": "111-111-1111",
"address": "102 foo st",
"city": "Nashville",
"state": "TN",
"zip_code": "23233",
"country": "USA",
"address_type": "Business",
"troubleshooting_reference": "dshjf",
"line_items": [
{
"type": "Unit",
"model_number": "123",
"serial_number": "222"
}
]
}
}
Having tried your code locally, I think what you're seeing is normal behaviour. I, too see the "Unpermitted parameters..." messages logged to the console, but the calls to parameters.permit do succeed and return filtered hashes as you expect. So I think if you check you'll find your code is actually working.
You can silence those messages by adding
ActionController::Parameters.action_on_unpermitted_parameters = false
either at the top of your class or in a file under config/initializers.

Resources