activemodel serializers with data as root when object is failed to save - ruby-on-rails

I'm using active model serializer for my API to serialize data models.
class Api::V1::UsersController < Api::V1::ApiController
include ::ActionController::Serialization
def create
user = User.new(user_params)
if user.save
return render json: user, status: :ok, root: :data
end
render_error(user.errors)
end
private
def user_params
params.require(:user).permit(:email, :password)
end
def render_error(errors, status = :unprocessable_entity)
meta = { count: errors.messages.count }
render json: errors, status: status, meta: meta, root: :data
end
end
When user parameters are valid and it is saved to DB, the API returns with data as root. For example:
{
"data": {
"id": 11
}
}
However, when parameters are not valid and the user object is not saved to DB, it returns without data as root. Example:
{
"email": [
"has already been taken"
]
}
I'm not sure what I'm missing, but I just want the API to return data as root for also failed scenario. Btw, the user serializer only includes id attribute.

You can specify it in the JSON:
def render_error(errors, status = :unprocessable_entity)
meta = { count: errors.messages.count }
render json: { data: errors }, status: status, meta: meta
end

Related

Rails API: how translate json request in spanish if my model is in english?

Model convention parameters need to be in English, but the input JSON request keys need to send it in Spanish, how is the best practice for rails to accept parameters in Spanish and save in database?
MODEL:
class Player < ApplicationRecord
validates :name, :level, :goals, :salary, :bonus, :team, presence: true
end
INPUT:
{
"jugadores" : [
{
"nombre":"Snow",
"nivel":"C",
"goles":10,
"sueldo":50000,
"bono":25000,
"sueldo_completo":null,
"equipo":"rojo"
},
{
"nombre":"JC",
"nivel":"A",
"goles":30,
"sueldo":100000,
"bono":30000,
"sueldo_completo":null,
"equipo":"azul"
}
]
}
Controller:
...
def create
#player = Player.new(player_params)
if #player.save
render json: #player, status: :created, location: #player
else
render json: #player.errors, status: :unprocessable_entity
end
end
...
def player_params
params.permit( jugadores: [ :nombre, :nivel, :goles, :salario, :bono, :salario_completo, :equipo ] )
end
...
thnx
Ill tried to translate with I18n, but I can't solve translate ActiveController
$"translation missing: en.{"jugadores"=>{"name"=>"Irving"}}"

Rails 5 manage result from monads

I've got Rails 5 app with dry-monads on board. Monads are used to create the Appointment object inside create action in AppointmentsController. They return Success or Failure in the last step with below structure:
# services/appointments/create.rb
(...)
def call
Success(appointment_params: appointment_params)
(...)
.bind(method(:save_appointment))
end
private
def save_appointment(appointment)
if appointment.save
Success(appointment)
else
Failure(failure_appointments: appointment, appointments_errors: appointment.errors.full_messages)
end
end
After each action (success or failure) I want to send an email and display the corresponding json in AppointmentsController:
class Api::AppointmentsController < ApplicationController
def create
succeeded_appointments = []
failure_appointments = []
appointments_errors = []
batch_create_appointments_params[:_json].each do |appointment_params|
appointment = ::Appointments::Create.new(appointment_params).call
if appointment.success?
succeeded_appointments << appointment.value!
else
failure_appointments << appointment.failure[:failure_appointments] &&
appointments_errors << appointment.failure[:appointments_errors]
end
end
if failure_appointments.any?
AppointmentMailer.failed_mail(email, failure_appointments.size, appointments_errors).deliver_now
render json: {
error: appointments_errors.join(', '),
}, status: :bad_request
elsif succeeded_appointments.any?
AppointmentMailer.success_mail(email, succeeded_appointments.size).deliver_now
render json: {
success: succeeded_appointments.map do |appointment|
appointment.as_json(include: %i[car customer work_orders])
end,
}
end
end
I wonder if there is a better, faster way to record these errors than declaring 3 different empty arrays (succeeded_appointments, failure_appointments, appointments_errors) like at the beginning of create action? so far the create action looks heavy.
Create a separate service object for bulk creation:
# services/appointments/bulk_create.rb
class Appointments::BulkCreate
def initialize(bulk_params)
#bulk_params = bulk_params
end
def call
if failed_results.any?
AppointmentMailer.failed_mail(email, failed_results_errors.size, failed_results_errors).deliver_now
Failure(failed_results_errors.join(', '))
else
AppointmentMailer.success_mail(email, success_appointments.size).deliver_now
Success(success_appointments)
end
end
private
attr_reader :bulk_params
def failed_results
results.select(&:failure?)
end
def success_results
results.select(&:success?)
end
def success_appointments
#success_appointments ||= success_results.map do |appointment|
appointment.as_json(include: %i[car customer work_orders])
end
end
def failed_results_errors
#failed_results_errors ||= failed_results.map do |failed_result|
failed_result.failure[:appointments_errors]
end
end
def results
#results ||= bulk_params.map do |appointment_params|
::Appointments::Create.new(appointment_params).call
end
end
end
Then your controller will look like this:
class Api::AppointmentsController < ApplicationController
def create
result = ::Appointments::BulkCreate.new(batch_create_appointments_params[:_json]).call
if result.success?
render json: { success: result.value! }, status: :ok
else
render json: { error: result.failure }, status: :bad_request
end
end
end

How to render a jsonapi-resources response in an custom controller action?

I have implemented my own object creation logic by overriding the create action in a JSONAPI::ResourceController controller.
After successful creation, I want to render the created object representation.
How to render this automatically generated JSON API response, using the jsonapi-resources gem?
Calling the super method does also trigger the default resource creation logic, so this does not work out for me.
class Api::V1::TransactionsController < JSONAPI::ResourceController
def create
#transaction = Transaction.create_from_api_request(request.headers, params)
# render automatic generated JSON API response (object representation)
end
end
You could do something like this:
class UsersController < JSONAPI::ResourceController
def create
user = create_user_from(request_params)
render json: serialize_user(user)
end
def serialize_user(user)
JSONAPI::ResourceSerializer
.new(UserResource)
.serialize_to_hash(UserResource.new(user, nil))
end
end
this way you will get a json response that is compliant with Jsonapi standards
render json: JSON.pretty_generate( JSON.parse #transaction )
def render_json
result =
begin
block_given? ? { success: true, data: yield } : { success: true }
rescue => e
json_error_response(e)
end
render json: result.to_json
end
def json_error_response(e)
Rails.logger.error(e.message)
response = { success: false, errors: e.message }
render json: response.to_json
end
render_json { values }

Rails - format Time in API response

i have a model places in relationship with the model opening_times.
In my places_controller i have this:
def index
places = Place.all
if places
render json: {
status: :ok,
result: places.as_json(
only: [
:id,
:name,
],
include: [
{ opening_times: {only: [:dayWeek, :open, :close]}},
]
)
}
else
render json: { errors: 'invalid request' }, status: 422
end
end
private
def place_params
params.require(:place).permit(:user_id, :name)
end
The open and close columns in DB are time.
How can i force to return a format time as %H:%M?
I'm not developing on RoR 3+ years... fill free to fix if there is any problem
So can You try this:
places = Place.all.map {|place|
place.opening_times.map! {|opening_time|
opening_time[:open].strftime! "%H:%M"
opening_time[:close].strftime! "%H:%M"
}
}

Using Ajax to POST JSON object in rails, and save it to a database?

I've looked through a number of these types of problems, but i can't quite figure it out.I'm really new to ruby on rails. I'm creating an application in rails that administers a printer. Basically what I'm trying to do here is POST a json object using ajax from the frontend which is written in javascript to the backend which I'm writing in rails. Basically what happens is when a user decides to checkout and print something, the json object is sent to the server and a new rails object is created using the json object's data. I want to create a rails object containing the data from the json object.
My ajax, located in the frontend javascript. Note that this code is in a completely seperate application:
$.ajax({
beforeSend: function(xhr) {
toggleModal();
xhr.setRequestHeader("Authorization", "OAuth "+auth_header);
},
url:message.action,
async:true,
type:message.method,
dataType:'json',
contentType: 'application/json',
data: JSON.stringify(userSession),
error: function(data){
toggleModal();
$.mobile.changePage($("#page_thankyou"),{ transition: "slide"});
},
success: function(data){
toggleModal();
console.log(userSession);
$.mobile.changePage($("#page_thankyou"),{ transition: "slide"});
}
})
Here is the userSession Object:
userSession = {
"kiosk_session":{
"session_id":"",
"is_order":"",
"session_items":[]
}
};
In my Kiosk_session controller:
# POST /kiosk_sessions.json
def create
puts YAML::dump params
#kiosk_session = KioskSession.new(params[:kiosk_session])
respond_to do |format|
if #kiosk_session.save
format.html { redirect_to #kiosk_session, notice: 'Kiosk session was successfully created.' }
format.json { render json: #kiosk_session, status: :created, location: #kiosk_session }
else
format.html { render action: "new" }
format.json { render json: #kiosk_session.errors, status: :unprocessable_entity }
end
end
end
and my kiosk_session model:
class KioskSession < ActiveRecord::Base
attr_accessible :id, :is_order, :is_reprint, :reprint_reason, :price,
:paid, :printed, :print_date, :session_items_attributes, :kiosk_id
has_many :session_items
has_one :kiosk_kiosk_session
belongs_to :user
belongs_to :kiosk
accepts_nested_attributes_for :session_items
before_save :before_save_callback
def before_save_callback
new_KSS = KioskKioskSession.new(:kiosk_id => self.kiosk_id, :kiosk_session_id => self.id)
new_KSS.save
self.total_price
end
def total_price
#session_items.to_a.sum {|item| session_items.total_price}
#array to hold subtotals
price = 0.00
#finds each item in session
session_items = SessionItem.where(:kiosk_session_id => self.id)
#creates array of subtotals
session_items.each do |t|
#if t.price
t.set_price
price += t.price
end
self.price = price
end
end
oh and my POST route for creating a kiosk session is /kiosk_session#create
I know this code is a mess, but any help would be greatly appreciated.

Resources