Undefined method render in Rails controller - Trying to respond to Sendgrid with a 200 status code
Asked Answered
V

1

8

I'm using the Sendgrid Parse API along with the Griddler gem to accept incoming emails. For the most part, this works fine; however, if you don't respond to Sendgrid with a status code 200, they will assume that the app didn't correctly receive the POST request and keep trying to make a POST for 3 days. I'm trying to respond with a status code and am having issues.

In regular RESTful routes, you can do something like...

render :status => 200

However, this must be done in a controller to recognize the render method, I believe. Griddler suggests that you create an EmailProcessor model and use a 'process' method to deal with the email.

From what I understand, you can't use the render method in models. So, I created an EmailProcessorsController class with a class method as seen below.

class EmailProcessor < ActiveRecord::Base

  include ApplicationHelper

  def initialize(email)
    @email = email
    @to = email.to # this is an array
    @from = email.from
  end

  def process
    # do other stuff
    EmailProcessorsController.render_ok
  end
end 

class EmailProcessorsController < ActionController::Base

  def self.render_ok
    render :status => 200
  end
end

Below is the error I get from my app. It doesn't like the render method :(

NoMethodError (undefined method `render' for EmailProcessorsController:Class):
  app/controllers/email_processors_controller.rb:6:in `render_ok'
  app/models/email_processor.rb:16:in `process'

I'm a newer dev and this probably something uber simple, but I'm stuck. Any thoughts and comments on the problem as well as design are greatly appreciated. Thanks!

UPDATE!

Per the suggestion of @meagar I moved the render call to the controller as seen below, but now I get a different error, and I'm not sure what to make of it.

class EmailProcessorsController < ApplicationController

  def initialize(email)
    @email = email
    @to = email.to # this is an array
    @from = email.from
  end

  def process
    # do other stuff
    render :status => 200
  end
end 

Without the render call, I don't get an error. Here's the error I get when calling render...

Module::DelegationError (ActionController::RackDelegation#status= delegated to @_response.status=, but @_response is nil: #<EmailProcessorsController:0x000001063b1558 @email=#<Griddler::Email:0x00000106378ac8 @params={"headers"=>"Received: by mx-007.sjc1.send
Vtehsta answered 2/10, 2014 at 1:21 Comment(5)
Have you already tried inheriting EmailProcessorsController from ApplicationController instead of ActionController::Base?Prototherian
Actually, scratch that. It looks like render is defined in ActionController::Instrumentation. Try inheriting from that. See api.rubyonrails.org/classes/ActionController/…Prototherian
Did I say ActionController::Instrumentation? I meant AbstractController::Rendering. Don't listen to me -- I don't really understand where Rails gets render.Prototherian
I was inheriting from ActionController::Base because that is what ApplicationController inherits from, and inheriting from ApplicationController wasn't working. It was a shot in the dark that didn't work.Vtehsta
Update - When using Griddler properly, you don't have to respond with an ok or 200 status if it receives the email. Griddler appears to do this for you.Vtehsta
G
6

render is an instance method, not a class method. You need to instantiate an instance of your controller, but that won't work regardless.

It's a serious error to try to render from your model. The model has no idea there is an HTTP request involved. Your controller should be creating your model, invoking whatever action on it, waiting for success, and then your controller should be rendering a response. What you're trying to do is fundamentally broken.

Gloucester answered 2/10, 2014 at 1:58 Comment(1)
That makes sense @meagar. I'm not sure why both the Sendgrid and Thoughtbot folks (they both wrote articles on integrating Thoughtbot's griddler gem to process incoming email) suggest having an EmailProcessor model class that deals with the email. It does seem like it would make more sense to have griddler call a controller action.Vtehsta

© 2022 - 2024 — McMap. All rights reserved.