Using ActionMailer on a controller method

Hi guys (and gals),

I have the most strange issue that I just cannot figure out. It
doesn’t make sense at all why it’s happening, and had a fellow Rails
developer friend of mine from the UK look at it with me last night,
and still couldn’t figure it out.

Ok, so I have a helpdesk ticketing system wrote in Rails 2.3.5. The
app itself has lots of models and controllers, respectively.

The 2 models in the app that I’m working with (well 3 considering the
mailer model), is Ticket and Customer. My mailer class is called
TicketMailer.

To make sense of it for you all, Ticket belongs_to Customer, Customer
has_many tickets. That’s the relationship between the two.

Tickets are created from the customer, so a user has to navigate to
the customer in the view and click on the create ticket, which nests
the customer_id into the ticket, which is saved to the ticket during
the create action.

With that said, I created the TicketMailer model, and what I am after,
is to deliver an e-mail to the customer when a ticket is created.

Here is my TicketMailer model:

class TicketMailer < ActionMailer::Base

def newticket(ticket)
ticket = @ticket
subject ‘A new ticket has been created for you’
recipients ticket.customer.email
from ‘[email protected]
sent_on Time.now
end

def ticketstatus(sent_at = Time.now)

subject ‘The status of your ticket has changed’

recipients ticket.customer.email

from ‘[email protected]

sent_on sent_at

end

end

The other method is commented out for now, as it hasn’t been
implemented, and so I will fight that battle later…

Here is the view of the e-mail, titled newticket.erb:


Hello <%= ticket.customer.first_name %>,

A new ticket titled “<%= ticket.title %>” has been created for you on
the Student Helpdesk Portal.

You can view your ticket at <%= link_to ticket %>.

You may submit comments on the ticket to provide questions or feedback
concerning the ticket.

As always, feel free to call us anytime at 1-866-888-3768, and we will
be happy to help.

Thank you for using the Student Helpdesk Portal, and have a great day.

Regards,

The Helpdesk Team


And here is my create action in my Tickets controller:

def create
@ticket = Ticket.new(params[:ticket])
@ticket.notes.first.user_id = current_user.id
TicketMailer.deliver_newticket(@ticket)
logger.debug("@@@ - Customer email is
#{@ticket.customer.email}")
respond_to do |format|
if @ticket.save
TicketMailer.create_newticket(@ticket)
TicketMailer.deliver_newticket(@ticket)
flash[:notice] = ‘Ticket was successfully created.’
format.html { redirect_to(@ticket) }
format.xml { render :xml => @cticket, :status
=> :created, :location => @ticket }
else
format.html { render :action => “new” }
format.xml { render :xml => @ticket.errors, :status
=> :unprocessable_entity }
end
end
end

For clarification, I placed the deliver above if @ticket.save for now
to get it working, since I don’t want new tickets getting created
before the mailer is working.

The problem I am having, is when I try to create a new ticket, I get
the error:

NoMethodError (undefined method customer' for nil:NilClass): app/models/ticket_mailer.rb:7:innewticket’
app/controllers/tickets_controller.rb:84:in `create’

Which I know simply put is telling me the customer doesn’t exist,
because customer_id would be nil, so there is no association. But
there is.

Here are the params that get passed into the create action. Not the
logger.debug message I put which just reiterates that the exact
attribute I’m calling is available.

Processing TicketsController#create (for 127.0.0.1 at 2010-03-21
00:05:11) [POST]
Parameters: {“ticket”=>{“platform_id”=>"", “title”=>“Testing
mailer”, “app_version”=>"", “app_id”=>"", “category_id”=>“5”,
“user_id”=>“2”, “os_version”=>"", “status_id”=>“1”, “desc”=>“Seeing if
the mailer works.”, “customer_id”=>“1”,
“notes_attributes”=>{“0”=>{“body”=>“Testing mailer.”}}},
“commit”=>“Create”, “action”=>“create”,
“authenticity_token”=>“lFPGXK8LdqYArXPb02lvF9RSywEiK1HehoPQv7etE/c=”,
“controller”=>“tickets”}
[4;36;1mUser Columns (3.4ms) [0m [0;1mSHOW FIELDS FROM
users [0m
[4;35;1mUser Load (0.6ms) [0m [0mSELECT * FROM users WHERE
(users.id = 2) LIMIT 1 [0m
[4;36;1mRole Load (1.5ms) [0m [0;1mSELECT roles.* FROM roles
INNER JOIN assignments ON roles.id = assignments.role_id WHERE
((assignments.user_id = 2)) [0m
[4;35;1mRole Columns (5.4ms) [0m [0mSHOW FIELDS FROM roles [0m
[4;36;1mTicket Columns (2.1ms) [0m [0;1mSHOW FIELDS FROM
tickets [0m
[4;35;1mNote Columns (1.9ms) [0m [0mSHOW FIELDS FROM notes [0m
[4;36;1mCustomer Columns (1.9ms) [0m [0;1mSHOW FIELDS FROM
customers [0m
[4;35;1mCustomer Load (0.4ms) [0m [0mSELECT * FROM customers
WHERE (customers.id = 1) [0m
@@@ - Customer email is [email protected]

ActionView::TemplateError (undefined method `customer’ for
nil:NilClass) on line #1 of app/views/ticket_mailer/newticket.erb:
1: Hello <%= @ticket.customer.first_name %>,
2:
3: A new ticket titled “<%= @ticket.title %>” has been created for you
on the Student Helpdesk Portal.
4:

app/views/ticket_mailer/newticket.erb:1
app/controllers/tickets_controller.rb:85:in `create'

Rendered rescues/_trace (141.3ms)
Rendered rescues/_request_and_response (0.7ms)
Rendering rescues/layout (internal_server_error)
[4;36;1mSQL (0.1ms) [0m [0;1mSET NAMES ‘utf8’ [0m
[4;35;1mSQL (0.1ms) [0m [0mSET SQL_AUTO_IS_NULL=0 [0m

As you can see, as I put in the create action, @ticket.customer.email
displayed the value in the logger.debug message. So, the customer is
made available to the new action before hand, so the customer is
already there for the create action.

The solution has got to be something silly that I am just not seeing.
If someone could help shed some light on this for me, I’d be much
appreciative.

Thanks,

Justin

On 21 March 2010 20:03, command0 [email protected] wrote:

The problem I am having, is when I try to create a new ticket, I get
the error:

NoMethodError (undefined method customer' for nil:NilClass): app/models/ticket_mailer.rb:7:in newticket’
app/controllers/tickets_controller.rb:84:in `create’

Which I know simply put is telling me the customer doesn’t exist,
because customer_id would be nil, so there is no association. But
there is.

No, it’s telling you that the “ticket” variable (at line 7 of
ticket_mailer.rb) is nil, and NilClass objects don’t have a “customer”
method.

class TicketMailer < ActionMailer::Base
def newticket(ticket)
ticket = @ticket
subject ‘A new ticket has been created for you’
recipients ticket.customer.email
from ‘[email protected]
sent_on Time.now
end

I’d assume the problem is caused by the assignment in the first line
of the method; I’d guess it’s meant to read:
@ticket = ticket
…because as it is, it doesn’t make much sense to pass in a ticket
parameter and then immediately overwrite it with an instance variable.

LOL yeah, I was so tired when I was working on this earlier this
morning, I just totally overlooked that.

When I change the assignment, I get the “Need controller and action!”
error.

In the View, here is the whole verbage it spits out:

ActionController::RoutingError in Tickets#create

Showing app/views/ticket_mailer/newticket.erb where line #5 raised:

Need controller and action!

Here are the new params:


[4;35;1mSQL (0.1ms) [0m [0mSET NAMES ‘utf8’ [0m
[4;36;1mSQL (0.1ms) [0m [0;1mSET SQL_AUTO_IS_NULL=0 [0m

Processing TicketsController#create (for 127.0.0.1 at 2010-03-21
14:52:09) [POST]
Parameters: {“ticket”=>{“platform_id”=>"", “title”=>“Testing the
mailer”, “app_version”=>"", “app_id”=>"", “category_id”=>“5”,
“user_id”=>“2”, “os_version”=>"", “status_id”=>“1”, “desc”=>“Let’s see
what happens.”, “customer_id”=>“1”,
“notes_attributes”=>{“0”=>{“body”=>“Trying again.”}}},
“commit”=>“Create”, “action”=>“create”,
“authenticity_token”=>“s562boG7oXhkhgeurg4C2mKv/vrAgOg5V/zmZjibMZA=”,
“controller”=>“tickets”}
[4;35;1mUser Columns (49.2ms) [0m [0mSHOW FIELDS FROM
users [0m
[4;36;1mUser Load (0.7ms) [0m [0;1mSELECT * FROM users WHERE
(users.id = 2) LIMIT 1 [0m
[4;35;1mRole Load (0.4ms) [0m [0mSELECT roles.* FROM roles
INNER JOIN assignments ON roles.id = assignments.role_id WHERE
((assignments.user_id = 2)) [0m
[4;36;1mRole Columns (1.2ms) [0m [0;1mSHOW FIELDS FROM
roles [0m
[4;35;1mTicket Columns (1.8ms) [0m [0mSHOW FIELDS FROM
tickets [0m
[4;36;1mNote Columns (1.6ms) [0m [0;1mSHOW FIELDS FROM
notes [0m
[4;35;1mCustomer Columns (1.6ms) [0m [0mSHOW FIELDS FROM
customers [0m
[4;36;1mCustomer Load (0.8ms) [0m [0;1mSELECT * FROM customers
WHERE (customers.id = 1) [0m

ActionView::TemplateError (Need controller and action!) on line #5 of
app/views/ticket_mailer/newticket.erb:
2:
3: A new ticket titled “<%= @ticket.title %>” has been created for you
on the Student Helpdesk Portal.
4:
5: You can view your ticket at <%= link_to @ticket %>.
6:
7: You may submit comments on the ticket to provide questions or
feedback concerning the ticket.
8:

app/views/ticket_mailer/newticket.erb:5
app/controllers/tickets_controller.rb:84:in `create'

Rendered rescues/_trace (147.5ms)
Rendered rescues/_request_and_response (0.5ms)
Rendering rescues/layout (internal_server_error)

From the sounds of it, it’s a routing issue, which seems a bit odd…

On 21 March 2010 21:01, command0 [email protected] wrote:

5: You can view your ticket at <%= link_to @ticket %>.

Do you have “map_resources :tickets” in your routes.rb file?

On 21 March 2010 21:29, command0 [email protected] wrote:

I have:

map.resources :tickets, :has_many => [:notes, :comments]

In routes.rb.

5: You can view your ticket at <%= link_to @ticket %>.

Okay,
So when we get to line 5 of app/views/ticket_mailer/newticket.erb,
you’re passing the @ticket variable to the link_to helper… so what’s
the value of @ticket at this stage? Is it actually a “Ticket” object,
or is it Nil?

I have:

map.resources :tickets, :has_many => [:notes, :comments]

In routes.rb.

The value of @ticket is represted as an array of all the attributes of
the ticket itself.

I just realized that. I had to change my link_to arguments just
slightly…