Search code examples
ruby-on-railsactionmailerprawn

Pdf invoice and Mailer in Rails


I try to learn Rails and I'm stuck. I have User, Job, Invoice and Customer models. I'm creating an invoice and Pdf invoice with Prawn. The Pdf invoice is not saved(I don't want to save pdf's, just to see the pdf in browser) and now I want a button to send pdf invoice by email. I have in invoice show view 2 buttons one for view Pdf and another send pdf by email.

= link_to 'View PDF', invoice_path(@invoice, format: "pdf")
\|
= link_to "Send Email", invoice_mail_path(current_user, @invoice), class: "btn btn-xs btn-primary"

I have:

invoice_mailer.rb

default from: "example@yahoo.com"

  def invoice_mail(invoice, user, job)
    @invoice = invoice
    @user = user
    @job = job
    attachments["#{(@invoice.invoice_number)}.pdf"] = InvoicePdf.new(@invoice, view_context).render

    mail(to: 'example@yahoo.com',
         subject: "A new invoice from xxx")
  end

invoices_controller.rb

def invoice_mail

# @invoice = Invoice.last
@invoice = Invoice.new(@invoice)
@user = current_user
@job = current_user.jobs

InvoiceMailer.invoice_mail(@invoice, @user, @job).deliver_now

flash[:notice] = "Invoice has been sent."
redirect_to invoices_path 
end

routes.rb

get :invoice_mail, to: 'invoices#invoice_mail', as: :invoice_mail

In invoices_controller in def invoice_mail if I have

@invoice = Invoice.last

is working and is sending the email with pdf attached but is grabbing the last invoice. If I have

@invoice = Invoice.new(@invoice)

is give me error.

What do I need instead of @invoice = Invoice.last to grab the current invoice ? Or what I did wrong ?

When i hit send email button I have on terminal :

Started GET "/invoice_mail.16-446cd684-c756-4ea3-a820-17756f44098d" for 127.0.0.1 at 2019-03-22 11:07:30 -0400
Processing by InvoicesController#invoice_mail as 
User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 2], ["LIMIT", 1]]
↳ /Users/ovi_tsb/.rvm/gems/ruby-2.4.1/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
Completed 404 Not Found in 2ms (ActiveRecord: 0.4ms)



ActiveRecord::RecordNotFound (Couldn't find Invoice without an ID):

app/controllers/invoices_controller.rb:124:in `invoice_mail'

Solution

  • @invoice = Invoice.new(@invoice)
    

    This, in your controller, makes no sense. You're assigning a @invoice a nil value to the value of Invoice.new(@invoice), which is the equivalent of Invoice.new(nil). That shouldn't throw any errors, but it really doesn't make sense to do.

    Presumably, what you want to do is find an invoice based on ID. Just like:

    @invoice = Invoice.find(params[:id])
    

    That means your request should include an :id parameter. If it does not, you need to include it. But I believe this should have it:

    = link_to "Send Email", invoice_mail_path(current_user, @invoice), 
                            class: "btn btn-xs btn-primary"
    

    Secondly, the link_to above need not include a current_user. current_user is a reference to the User grabbed by Rails via the user's session. In other words, it'll exist in your controller by default. So don't bother passing it:

    = link_to "Send Email", invoice_mail_path(@invoice), 
                             class: "btn btn-xs btn-primary"
    

    Lets clean up your controller with this new information:

    def invoice_mail
      @invoice = Invoice.find(params[:id]) # :id should be the invoice ID
      @jobs = current_user.jobs
    
      InvoiceMailer.invoice_mail(@invoice, current_user, @jobs).deliver_now
      flash[:notice] = "Invoice has been sent."
      redirect_to invoices_path 
    end