API Controller Specifically for shared methods

Viewed 183

Would it be best practice to create some sort of 'general api controller' for shared methods among different models in my RoR application? For example I'm including email validation for Customers - once the user finishes typing in the email address (before submit), an $.ajax POST request is sent to the customers_controller where an external API is being called. After parsing the response I return a response back depending on certain conditions. The validation is handled in real time on the front end before submitting so that the user can know if an email address is valid or not before submitting. The controller method is below.

  def validate_email_address
    response = ValidateEmailAddressJob.perform_now(params[:email], "Agentapp")
    data = JSON.parse response.body

    if data['result']['verdict'] == "Valid" || data['result']['verdict'] == "Risky"
      html = "<div class='text-success'><i class='fa fa-check'></i> This email appears to be valid</div>"
      render json: {html: html, result: data['result']}, status: 200
    elsif data['result']['verdict'] == "Invalid"
      html = "<div class='text-warning'><i class='fa fa-exclamation'></i> This email may be invalid</div>"
      render json: {html: html, result: data['result']}, status: 200
    else
      render json: {}, status: 503
    end
  end

I'm trying to keep my code as DRY as possible, so if I wanted to share this email_validation controller method with VendorContacts for example, I'm thinking I could just point the other VendorContact API call to /customers/validate_email_address endpoint even if it's not technically a customer that's needing the validation? Or I could just copy and paste the controller method into the vendor_contacts_controller? Or I could create a separate general api controller with an endpoint such as /validation/emailaddress.

Thanks ahead of time for any help, I'm just trying to learn what the appropriate way to handle this situation would be.

1 Answers

I don't know if this would be considered "best practice" but as a long-time Rails dev, my approach would be to create an EmailController controller, with a single action create, and an Email model (not inheriting from ActiveRecord::Base).

class EmailController < ApplicationController
  def create
    email = Email.new(params[:email])
    if email.valid?
      render partial: :valid_email_response
    else
      render partial: :invalid_email_response
    end
  end
end

So the Email model has an initialize method, and a valid? method, and the html response is contained in separate view files. Of course, nothing is saved to the database here. The EmailController#create action is invoked any time you wish to validate an email address.

My rationale is that controllers should implement CRUD methods, and in this case a model should handle the validation. I believe this is entirely consistent with the "Rails Way".

IMHO Rails controllers can become catch-all classes for all kinds of application logic, and that coercing the logic into MVC format makes the cleanest code.

Related