In my application the render is not showing the response on browsers console.
my controller class is-
def create
ActionItem.transaction do
#action = #doc.action_items.new(action_item_params)
#action.minutes_section = #section if #section
# Were we passed a sort_order? If not, default to the highest sort
# order number for this action item's section. minutes-app may
# also pass us -1 to indicate we should compute the next value.
if !action_item_params.key?(:sort_order) or [-1, nil, ""].include?(action_item_params[:sort_order])
result = ActionItem.where(minutes_document_id: #doc.id, minutes_section_id: #section.id).maximum('sort_order')
if result.nil?
#action.sort_order = 0
else
#action.sort_order = result + 1
end
end
if #action.save!
#action.action_items_statuses.create!(status: 'incomplete', status_type: 'completion', contact_id: current_user.id)
#action.action_items_statuses.create!(status: 'unsent', status_type: 'notification', contact_id: current_user.id)
#action.action_items_statuses.reload
handle_assignees(#action, params[:data][:attributes][:assignees]) if !params[:data][:attributes][:assignees].blank?
handle_note(#action, params[:data][:attributes][:note])
render(json: #action, status: 201)
else
render(json: { error: #action.errors }, status: 500)
end
end
rescue ActiveRecord::ActiveRecordError => e
Rails.logger.error e.message
render(json: { error: e.message }, status: 500)
end
I am not getting the response on console-
Error
Related
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
I am dealing with Shopify order creation webhooks and it is triggering multiple times.
def perform(shop_domain:, webhook:)
shop = Shop.find_by(shopify_domain: shop_domain)
found = false
order_item_ids = []
webhook['line_items'].each do |line_item|
line_item['properties'].each do |property|
if property['name'] == 'BJ_PROD'
found = true
order_item_ids << line_item['product_id']
end
end
end
if found
#order = Order.create({
shop: shop,
shopify_order_id: webhook["id"],
status: 'Ordered',
sent_to_admin: false,
order_details: webhook
})
end
session = ShopifyAPI::Session.new(shop.shopify_domain, shop.shopify_token)
session = ShopifyAPI::Base.activate_session(session)
order_item_ids.each do |order_item_id|
product = ShopifyAPI::Product.find(order_item_id)
product.published_at = nil
product.save!
end
shop.with_shopify_session do
end
render status: 200, json: #order.to_json
end
I am trying to use render status: 200 and head :ok in my OrdersCreateJob class but it is giving error as it is being used in the background job.
Does anybody have an idea of how to deal with such scenarios?
I'm trying to assign a value to current_user in GraphqlController but it's not working.
this is my code in graphql_controller.rb
class GraphqlController < ApplicationController
# If accessing from outside this domain, nullify the session
# This allows for outside API access while preventing CSRF attacks,
# but you'll have to authenticate your user separately
# protect_from_forgery with: :null_session
def execute
variables = ensure_hash(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
session: session,
current_user: current_user
}
result = GraphqlSimpleLoginAppSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
rescue => e
raise e unless Rails.env.development?
handle_error_in_development e
end
private
def current_user
return unless session[:token]
AuthToken.verify(session[:token])
end
# Handle form data, JSON body, or a blank value
def ensure_hash(ambiguous_param)
case ambiguous_param
when String
if ambiguous_param.present?
ensure_hash(JSON.parse(ambiguous_param))
else
{}
end
when Hash, ActionController::Parameters
ambiguous_param
when nil
{}
else
raise ArgumentError, "Unexpected parameter: #{ambiguous_param}"
end
end
def handle_error_in_development(e)
logger.error e.message
logger.error e.backtrace.join("\n")
render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500
end
end
but current_user remains null. I don't know why. Please can you help me ?
I use gem stripe_event with stripe webhook.
My initial code is:
config/initializers/stripe.rb
StripeEvent.configure do |events|
events.subscribe 'checkout.session.completed', StripeCheckoutSessionService.new
end
app/services/stripe_checkout_session_service.rb
class StripeCheckoutSessionService
def call(event)
order = Order.find_by(checkout_session_id: event.data.object.id)
order.update(state: "paid")
end
end
My problem is that if order is nil, I have a 500 error, and I want to have a 422 error instead.
I try that :
app/services/stripe_checkout_session_service.rb
class StripeCheckoutSessionService
def call(event)
order = Order.find_by(checkout_session_id: event.data.object.id)
if order
order.update(state: "paid")
head :accepted
else
head :unprocessable_entity
end
end
end
head is not recognize by the service, I try to return a string instead and return head directly in the block but I'm locked now...
Does anybody have any idea for me ?
If you want to return a string, probably you can do this:
class StripeCheckoutSessionService
def call(event)
order = Order.find_by(checkout_session_id: event.data.object.id)
if order
order.update(state: "paid")
"Successfully updated!" # or do this { status: 400, msg: 'success' }
else
"Error occurred!" # or do this { status: 422, msg: 'unprocessable_entity' }
end
end
end
Haven't tried this but should work.
Sometime one in a long series of events within a controller action fails. For example, a credit card is processed but then an ActiveRecord query times out. Is there any way to make those calls reversible?
E.g. with this controller action:
def process_order
cart = Cart.new(params[:cart])
load_order
response = credit_card.charge
if response
submit_order
order.receipt = Pdf.new(render_to_string(:partial => 'receipt')
order.receipt.pdf.generate
order.receipt.save
render :action => 'finished'
else
order.transaction = response
#message = order.transaction.message
order.transaction.save
render :action => 'charge_failed'
end
end
I would like to be able to put a block around it like so:
def process_order
transaction
cart = Cart.new(params[:cart])
load_order
response = credit_card.charge
if response
submit_order
order.receipt = Pdf.new(render_to_string(:partial => 'receipt')
order.receipt.pdf.generate
order.receipt.save
render :action => 'finished'
else
order.transaction = response
#message = order.transaction.message
order.transaction.save
render :action => 'charge_failed'
end
rollback
credit_card.cancel_charge
...
end
end
This is just a contrived example and I'm not really sure how it would work in practice. What typically happens is we get an exception like ActiveRecord::StatementInvalid: : execution expired for the line with submit_order and then we have to go and manually run the rest of the lines that should have run.
Here's a generic solution.
class Transactable
def initialize(&block)
raise LocalJumpError unless block_given?
#block = block
end
def on_rollback(&block)
raise LocalJumpError unless block_given?
#rollback = block
self
end
def call
#block.call
end
def rollback
#rollback.call if #rollback
end
end
class Transaction
def initialize(tasks)
tasks = Array(tasks)
tasks.each do |t|
Transactable === t or raise TypeError
end
#tasks = tasks
end
def run
finished_tasks = []
begin
#tasks.each do |t|
t.call
finished_tasks << t
end
rescue => err
finished_tasks.each do |t|
t.rollback
end
raise err
end
end
end
if __FILE__ == $0
Transaction.new([
Transactable.new { puts "1: call" }.on_rollback { puts "1: rollback" },
Transactable.new { puts "2: call" }.on_rollback { puts "2: rollback" },
Transactable.new { puts "3: call"; raise "fail!" }.on_rollback { puts "3: rollback" },
]).run
end
Note that it doesn't:
handle errors in the rollback block
call the rollback for the failed task, but that's easy to adjust
Just wrap it in
cart.transaction do
# ...
end
to use transactions. For details see http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
I'm a bit late but I think you should use save! instead of save. save just returns false if something fails within your model but save! raises an exception and your ActiveRecord::Base.transaction do block rolls back your changes correctly...
For example:
def process_order
ActiveRecord::Base.transaction do
begin
cart = Cart.new(params[:cart])
load_order
response = credit_card.charge
if response
submit_order
order.receipt = Pdf.new(render_to_string(:partial => 'receipt')
order.receipt.pdf.generate
order.receipt.save!
render :action => 'finished'
else
order.transaction = response
#message = order.transaction.message
order.transaction.save!
render :action => 'charge_failed'
end
rescue
# Exception raised ... ROLLBACK
raise ActiveRecord::Rollback
end
end