Reputation: 485
I am working on a Rails API backend with a separate Rails/Angular front-end codebase. The responses from the Rails API must be structured in a certain way to match with the front-end flash messages. A(n) (slightly boiled down) example controller response is
render json: {status: "Unauthorized", code: "AUTH.UNAUTHORIZED", fallback_msg: "Unauthorized request"}
so basically all my controllers are full of this, and sometimes when there are 5 possible responses for a method (ex: if a user resets their email the response can be invalid password, invalid email, email is already registered etc). A coworker suggested abstracting these methods out into the model, so the model is response for sending back these messages and then the controller can just have
def ctrl_method
user = User.update(password: password)
render json: user, status(user)
end
(where status is another method that provides the HTTP status code based on the object's status attribute)
My question is is this best practice? I understand Rails MVC and feel like the responsibility of sending the json message belongs to the controller not the model.
Upvotes: 2
Views: 2515
Reputation: 536
Without knowing any more details, I would think about utilizing concerns to deal with the statuses. This allows business logic to be encapsulated without muddying up your models. So you could have
module Concerns
module Statuses
def deal_with_show
# business logic goes here to generate the status
end
def deal_with_index
# business logic goes here to generate the status
end
def deal_with_create
# business logic goes here to generate the status
end
def default_status
# set a default status here
end
end
end
and then in the controllers
class MyController < ApplicationController
include Concerns::Statuses
def index
render json: deal_with_index
end
end
Of course, that breakdown of statuses in the concern is arbitrary. It can be handled however makes sense: by method, by verb, or by some other distinction.
This is a good bit on concerns.
Upvotes: 0
Reputation: 191
If you want to deal with ActiveRecord errors I think you use errors.full_messages
and use the same code and status for such errors (status: 'Forbidden', code: '').
Note that you should customize your messages in locale files see guide. But it's useful if you want to translate your app in different languages.
Success messages can be inferred from the controller and the action (see below).
class ApplicationController < ActionController::Base
...
def render_errors(object)
render json: {status: 'Forbidden', code: 'WRONG_DATA', fallback_msg: object.errors.full_messages.join(", ")}
end
def render_success(message = nil)
message ||= I18n.t("#{self.controller_name}.message.#{self.action_name}"
render json: {status: 'OK', code: 'OK', fallback_msg: message}
end
end
class SomeController < ApplicationController
def update
if @some.update(params)
render_success
else
render_errors(@some)
end
end
end
Upvotes: 0
Reputation: 10763
I say you're both right. The controller should have the responsibility of sending the message, and the methods should be abstracted out--just not into the model, more like a class that lives in /lib
.
This should make testing easier as well.
Upvotes: 1