I am developing a rails app with this method in it:
PUT /newsletters/1;send
def sendmails
newsletter = Newsletter.find_by_id_and_sent(params[:id], false)
users = User.find(:all)
raise users.to_yaml #debugger
users.each do |user| #evaluates to nil.each - debug
Notifier.deliver_newsletter(user, newsletter)
end
newsletter.update_attribute(‘sent’, true)
redirect_to newsletters_path
end
I get an error saying that users.each do |user| evaluates to nil.each,
and that I probably expected an Array object there. This is true, I did
expect an Array object. Thing is, now I’ve tried to debug the code with
both debugger and raise to_yaml, and both times the users variable
evaluates to a perfect Array of 3 Users, exactly in correspondence with
the DB! I have also tried to debug the user variable and it evaluates to
a User with id 1, meaning the iterator fetches that user successfully
from the Array.
Yet after the first iteration, I get an error / crash.
I have tried to change users to @users, with the exact same result.
Debugging shows an Array of 3 user objects. The app crashes.
users.each do |user| #evaluates to nil.each - debug
In general, you need to cut your action up into tiny methods and write
unit
tests on each one. They incredibly reduce the odds of exactly this kind
of
drama! Then the methods should run in the model layer, and the
controller should
only call into the model.
Specifically, check if ‘users’ is aliased anywhere else, such as to a
method.
Then try this:
(users || []).each
That will force a nil users to behave like an empty array. .find(:all)
should
naturally return an empty array if you have no users, so you should not
need
this tweak. But it lets you manually debug more:
Hello Vahagn,
I suggest you do it as follows:
a) old-fashioned way by using puts liberally &
b) take baby steps
until it is debugged.
Your code with puts statements inserted; just an example:
def sendmails
newsletter = Newsletter.find_by_id_and_sent(params[:id], false)
users = User.find(:all)
# do not raise anything… confuses Ruby interpretor
puts users
users.each do |user|
puts user #Notifier.deliver_newsletter(user, newsletter)
end #newsletter.update_attribute(‘sent’, true) #redirect_to newsletters_path
end
Make sure first that the each iterator is printing your object instances
correctly. You can use “pp” short for pretty-print if you want but
then you will have to require it. puts is built into the language and
most of the times, it is sufficient.
This way, you can be absolutely sure that nothing unexpected is
happening with your basic loop. Once you are sure then you can
uncomment each statement one by one, e.g., uncomment Notifier… first
and test. If that works then go to newslettr.update…
class Notifier < ActionMailer::ARMailer
def newsletter(user, newsletter)
recipients user.email
from “MyApp [email protected]”
subject newsletter.subject
body :body => newsletter.body, :user => user
end
end
…and this is the file the stack trace refers to:
/app/views/notifier/newsletter.text.plain.rhtml:
My Newsletter
<%= render :inline => @body %>
Still - user is not being referenced from this file at all, so why the
error?