Does anyone have recommendations for how I can reduce respond_to
blocks? It seems like my JSON formatting takes up a considerable amount of space. The controller, for the most part, responds with HTML but this specific method is called via Ajax and responds in JSON:
def create
# initial setup
respond_to do |format|
unless paid_cash == true || PayPalPayments::OrderValidator.call(order_id)
format.json do
render json: {
status: :unhandled_error,
message: 'Invalid order ID supplied?'
}, status: 400
end
end
if @submitted_application.save(context: :create)
MembershipMailer.with(application: @submitted_application).signup_confirmation.deliver_later
format.json do
render json: {
status: :created,
modal: render_to_string(
partial: 'membership_confirmation_modal.html.erb'
)
}
end
else
format.json do
render json: {
status: :validation_errors,
errors: @submitted_application.errors
}, status: 400
end
end
end
end
If you're doing a lot of JSON responses, like you're building a JSON API, then it would make sense to make a method to simplify that pattern. For example, create a method like this:
def respond_json(content)
status = content[:status]
render(
json: content,
status: STATUS_CODE_REMAPPED[status] || status
)
end
Where that works with the structure you've established and uses it to generate the correct render
call. As this only works with data structured a specific way, it helps enforce consistency in your responses.
This depends on mapping the internal codes to the Rails response codes:
STATUS_CODE_REMAPPED = {
created: :ok,
unhandled_error: :bad_request,
validation_errors: :bad_request
}
Where using the symbol codes helps the code become more self-explanatory.
Another thing to note is your order verification could be extracted into a before_action
handler:
before_action :verify_order_id, only: [ :create ]
def verify_order_id
return if paid_cash || PayPalPayments::OrderValidator.call(order_id)
respond_json(
status: :unhandled_error,
message: 'Invalid order ID supplied?'
)
end
Where if that handler renders something the chain stops as the request is considered serviced.
This dramatically reduces how much code is left in the controller action:
def create
@submitted_application.save!(context: :create)
MembershipMailer.with(application: @submitted_application).signup_confirmation.deliver_later
respond_json(
status: :created,
modal: render_to_string(
partial: 'membership_confirmation_modal.html.erb'
)
)
rescue ActiveRecord::RecordInvalid
respond_json(
status: :validation_errors,
errors: @submitted_application.errors
)
end
I've used save!
here so that the expected path is much simpler, there's no branching. If/when an error occurs then you can go off into the exception handling area.
Consider adding a before_action
to validate that the requestor wants JSON and handle it there instead of stubbing in lots and lots of respond_to
calls in your controller actions.
Don't forget about rescue_from
which can blanket rescue from common problems like invalid request types and so on. This can also reduce how much repetitive code you have to do.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.