Question

I have problem with my application, when trying to send emails in the background I get error uninitialized constant AnswersController::LazyDoer , I don't have slightest clue why isn't it working, any suggestions?

My worker is in app/workers/lazy_doer.rb

Here is my controller:

class AnswersController < ApplicationController
  before_action :authenticate_user!
  before_action :set_question, except: [:adding_likes,:accept]

  def create
    @answer = Answer.new(answer_params)
    @answer.user_id = current_user.id
    @answer.question_id = @question.id
    @question_owner = User.find(@question.user_id)

    if @answer.save
      LazyDoer.perform_async(@question_owner,current_user,@answer,@question)
      redirect_to question_path(@question), notice: "Answer was successfully created."
    else    
      render(:template => "questions/show", alert: "There was an error when adding answer.")

    end
  end

Here you have my worker:

class LazyDoer
  include Sidekiq::Worker
  sidekiq_options retry: false

  def perform(question_owner,current_user,answer,question)
    @question_owner = question_owner
    @current_user = current_user
    @answer = answer
    @question = question
    UserMailer.send_email(@question_owner,@current_user,@answer,@question).deliver
  end
end

EDIT:

I made my LazyDoer worker fully operational , but now I have problem with sending email via it. What's most important , MAILER WORKS PERFECTLY WITHOUT SIDEKIQ. Here's the error inside sidekiq:

2014-07-30T19:28:38.479Z 4317 TID-amn3w LazyDoer JID-3e465606b1d5728181002af0 INFO: start
2014-07-30T19:28:38.480Z 4317 TID-amn3w LazyDoer JID-3e465606b1d5728181002af0 INFO: fail: 0.001 sec
2014-07-30T19:28:38.481Z 4317 TID-amn3w WARN: {"retry"=>false, "queue"=>"default", "class"=>"LazyDoer", "args"=>["matthew.kilan@gmail.com", "matthew.kilan@gmail.com", "#<Answer:0x000000045fd148>", "#<Question:0x000000045fe728>"], "jid"=>"3e465606b1d5728181002af0", "enqueued_at"=>1406748518.4762628}
2014-07-30T19:28:38.481Z 4317 TID-amn3w WARN: undefined method `email' for "matthew.kilan@gmail.com":String
2014-07-30T19:28:38.481Z 4317 TID-amn3w WARN: /home/mateusz/Pulpit/Aptana3_Workspace/challenge_app/app/mailers/user_mailer.rb:9:in `send_email'

And here you have my mailer:

class UserMailer < ActionMailer::Base
  default from: "matthew.kilan@gmail.com"

  def send_email(question_owner,cur_user,answer,question)
    @question_owner = question_owner
    @cur_user = cur_user
    @answer = answer
    @question = question
    mail(to: @question_owner.email, subject: "Answer added to your question:")
  end

  def accepted_email(user,answer,question)
    @user = user
    @answer = answer
    @question = question
    mail(to: @user.email, subject: "Your answer has been accepted")
  end
end
Was it helpful?

Solution

I have solution, the problem with Sidekiq error was that since it's using nosql database which is redis, redis can't properly understand complex rails data, like for example ActiveRecord Models, if you are trying to send to your worker let's say , whole user with every single attribute he has - this will not work in redis, data is way too complex. Solution is simple, look exactly at your generated email view and mailer.rb and see exactly which attributes you need, then when you need to call your worker send him ONLY those attributes, don't send whole ActiveRecord Models.

Here you have fixed worker:

class LazyDoer
  include Sidekiq::Worker
  sidekiq_options retry: false

  def perform(question_owner_email,current_user_name,answer_contents,question_title)
    UserMailer.send_email(question_owner_email,current_user_name,answer_contents,question_title).deliver
  end
end

Fixed controller (MOST IMPORTANT):

class AnswersController < ApplicationController
  before_action :authenticate_user!
  before_action :set_question, except: [:adding_likes,:accept]

  def create
    @answer = Answer.new(answer_params)
    @answer.user_id = current_user.id
    @answer.question_id = @question.id
    @question_owner = User.find(@question.user_id)

    if @answer.save
      LazyDoer.perform_async(@question_owner.email,current_user.name,@answer.contents,@question.title)
      #DLA MAILERA BEZ SIDEKIQ UserMailer.send_email(@question_owner,current_user,@answer,@question).deliver
      redirect_to question_path(@question), notice: "Answer was successfully created."
    else    
      #redirect_to question_path(@question), alert: "There was an error when adding answer."
      render(:template => "questions/show", alert: "There was an error when adding answer.")
    end
  end
end

Fixed user mailer:

class UserMailer < ActionMailer::Base
  default from: "matthew.kilan@gmail.com"

  def send_email(question_owner_email,cur_user_name,answer_contents,question_title)
    @question_owner_email = question_owner_email
    @cur_user_name = cur_user_name
    @answer_contents = answer_contents
    @question_title = question_title
    mail(to: @question_owner_email, subject: "Answer added to your question:")
  end
end

Fixed email view (with use of slim template language instead of erb):

doctype html
html
    head
        meta content="text/html; charset=UTF-8" http-equiv="Content-Type"
    body
        h1 Your question #{@question_title} has been answered
        p   
            |
                Answered by #{@cur_user_name}
                <br />
                The answer content is:
                <br />
                #{@answer_contents}

        p Accept or like the answer if it was useful for you.

OTHER TIPS

Instead of sending user object in @question_owner send user id.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top