Differences in execution between console and app

class AppointmentBook < ActiveRecord::Base

has_many :appointments

def lookup(date, look_ahead = 27)
return nil unless block_given?

(date..date + look_ahead).each do |date|
  yield(date, appointments.find_all_by_date(date))
end

end

end

The line with yield is throwing the error:
undefined method ‘each’ for #<Date: 4908761/2,0,2299161>

A YAML dump of date yields:

DATE: — 2007-10-07 (CLASS: Date)

However, a very similar line of code works fine in console:
appointment_book.appointments.find_all_by_date(Date.today) # []

The empty array is expected.

The kicker: if I call #to_s on date inside my method, it works. But I
shouldn’t have to call #to_s.

Any ideas?

Rick Denatale wrote:

What do you EXPECT this to do?

Return an array.

Assuming that date is a Date then date+lookahead is also going to be a
Date.

Dates aren’t enumerable, and don’t have an each method.

True, Dates are not enumerable, but ranges are, and they respond to
each:

(date…date + look_ahead).class # Range
(date…date + look_ahead).respond_to? :each # true

If you want this to yield each appointment with a date look_ahead days
from date, then you probably want something like:

def lookup(date, look_ahead = 27)
return nil unless block_given?

 appointments.find_all_by_date(date..date + look_ahead).each do

|appointment|
yield appointment
end
end

That achieves a similar effect, but I want my appointments to be grouped
by date. True there are other ways to group by date, but it makes my
views easier if I get a date and a collection of appointments on that
date. View:

<% @tattoo_artist.appointment_book.lookup(@date) do |date, appointments|
%>

<%= date.strftime('%A') %><%= ' (Today)' if date.eql?(Date.today) %>

<%= date.strftime('%B %d, %Y') %>

<% appointments.each do |appointment| %>

<%= appointment.time %> with <%= appointment.client.name %>
<%= appointment.description %>

<% end %>
<% end %>

In other words, I want:

Date
Appointment for that date
Appointment for that date
Appointment for that date
Date
Appointment for that date

Even if I were to use SQL to group the results by date, I’d have to
perform extra manipulation to get the above effect. In this case I
prefer cleanliness over efficiency.

You can’t create a Range over 2 Dates and iterate over those - I’m
assuming that’s what you want to do.

but what you can do is iterate over the lookahead

(0…look_ahead).each do |diff|
yield (date+diff…)
end

On 7 Okt., 20:24, Daniel W. [email protected]

[email protected] wrote:

You can’t create a Range over 2 Dates and iterate over those - I’m
assuming that’s what you want to do.

(Date.today…Date.today + 10).each do |date|
?> puts date

end
2007-10-07
2007-10-08
2007-10-09
2007-10-10
2007-10-11
2007-10-12
2007-10-13
2007-10-14
2007-10-15
2007-10-16
2007-10-17
=> #<Date: 4908761/2,0,2299161>…#<Date: 4908781/2,0,2299161>

On 10/7/07, Daniel W. [email protected] wrote:

end

end

end

The line with yield is throwing the error:
undefined method ‘each’ for #<Date: 4908761/2,0,2299161>

What do you EXPECT this to do?

Assuming that date is a Date then date+lookahead is also going to be a
Date.

Dates aren’t enumerable, and don’t have an each method.

If you want this to yield each appointment with a date look_ahead days
from date, then you probably want something like:

def lookup(date, look_ahead = 27)
return nil unless block_given?

 appointments.find_all_by_date(date..date + look_ahead).each do

|appointment|
yield appointment
end
end

The kicker: if I call #to_s on date inside my method, it works. But I
shouldn’t have to call #to_s.

to_s will return a string representation of the date. Strings DO have
an each method which when called without an argument yields each “\n”
delimited line in the string.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 10/7/07, Daniel W. [email protected] wrote:

end

However, a very similar line of code works fine in console:

It’s not a problem of iterating over the range, cause as you’ve
pointed out you can iterate over a range of dates.

Looks like it’s either a bug in the client code or maybe something
weird about AR’s #find_all_by

I would simplify this in order to debug. First just yield the date
itself and don’t worry about the appointments. Take out all the
appointment display code.

The other possibility (unlikely though) is some weirdness in
find_all_by like I said. Try changing the call to
appointments.find(:all, :conditions => [“date=?”, Date.today])

but as you can see, you’re iterating through the dates fine. There’s
just something strange happening in the code that’s being called via
yield, or perhaps something funky under the hood.

Pat

[email protected] wrote:

You can’t create a Range over 2 Dates and iterate over those - I’m
assuming that’s what you want to do.

but what you can do is iterate over the lookahead

(0…look_ahead).each do |diff|
yield (date+diff…)
end

I think we’ve gotten a little off-track. Allow me to steer us back in
the right direction…

This is the line throwing the error in my app:

appointments.find_all_by_date(date)

In console, that same line works fine.

I’ve logger.debugged date in my method and it looks like a date.

I’ve even pulled that line out of the yield and made it the first line
in my method and that line is where it fails:

def lookup(date, look_ahead = 27)
logger.debug("\n\n>>> DATE: #{ date.class }" # Yup, it’s a date.
appointments.find_all_by_date(date) # Dies here now…

return nil unless block_given?

(date…date + look_ahead).each do |date|
yield(date, appointments.find_all_by_date(date)) # …instead of
here.
end
end

ok i seems you sometimes CAN create ranges of dates - but that it
doesn’t work in a running app points towards some strange view-helpers
being added to the date-class or something like that.
my method should still work, while yours implies some kind of hidden
to_i/to_date back-and-forth which could lead to that error. don’t try
to force it if there is another way.

Phil

On 7 Okt., 22:11, Daniel W. [email protected]

On 7 Oct 2007, at 21:19, Daniel W. wrote:

I think we’ve gotten a little off-track. Allow me to steer us back in
the right direction…

This is the line throwing the error in my app:

appointments.find_all_by_date(date)

What’s the stack trace of the error?

Fred

ah … yes sorry I seem to be responding while new and clarifying
messages are added to this thread… that way I got off-track.

have you tried converting the date to a string before the
find_all_by_date() ?
or formulating it as a :conditions array ?

these are not solutions but you could analyse the problem from
different angles like that.

P

On 7 Okt., 22:19, Daniel W. [email protected]

Pat M. wrote:

I would simplify this in order to debug. First just yield the date
itself and don’t worry about the appointments. Take out all the
appointment display code.

The other possibility (unlikely though) is some weirdness in
find_all_by like I said. Try changing the call to
appointments.find(:all, :conditions => [“date=?”, Date.today])

Good suggestions Pat. And the situation gets weirder. I tried specifying
conditions as you suggested and get the same error.

@removed_email_address@domain.invalid:
I tried iterating through 0…look_ahead and adding the difference to
date and still get the same error.

Frederick C. wrote:

What’s the stack trace of the error?

Stack trace: http://pastie.caboo.se/104710

Daniel W. wrote:

Frederick C. wrote:

What’s the stack trace of the error?

Stack trace:

http://pastie.caboo.se/104710

On 10/7/07, Daniel W. [email protected] wrote:

Good suggestions Pat. And the situation gets weirder. I tried specifying
href=“Parked at Loopia”>Parked at Loopia
Oh, yeah, weird. I would just change it to
appointments.find_all_by_date Date.today.to_s(:db)

and cross my fingers.

Pat

Pat M. wrote:

Oh, yeah, weird. I would just change it to
appointments.find_all_by_date Date.today.to_s(:db)

and cross my fingers.

Pat

What does the (:db) to?

On 10/7/07, Daniel W. [email protected] wrote:

Daniel W. wrote:

Frederick C. wrote:

What’s the stack trace of the error?

Stack trace:

Parked at Loopia

What database are you using? Version, and adapter version? It looks
like AR isn’t treating something as a date there. Like it’s
sanitizing the SQL as a string…which most likely means (to me) that
for some reason it doesn’t know that the db column is a date. Did you
perhaps mess up on the migration and create the date field as a string
instead of a date?

Pat

On 7 Oct 2007, at 21:45, Daniel W. wrote:

Pat M. wrote:

Oh, yeah, weird. I would just change it to
appointments.find_all_by_date Date.today.to_s(:db)

and cross my fingers.

Pat

What does the (:db) to?

ActiveSupport overrides Date#to_s, passing :db makes it format the
string in the way the database wants it.
Fred

Pat M. wrote:

What database are you using? Version, and adapter version? It looks
like AR isn’t treating something as a date there. Like it’s
sanitizing the SQL as a string…which most likely means (to me) that
for some reason it doesn’t know that the db column is a date. Did you
perhaps mess up on the migration and create the date field as a string
instead of a date?

MySQL. Not sure what version. I’m on OS 10.4 – anyone know how to
check?

I assume I’m using the the mysql gem adapter. gem list:

mysql (2.7)
MySQL/Ruby provides the same functions for Ruby programs that the
MySQL C API provides for C programs.

Schema for appointments:

create_table “appointments”, :force => true do |t|
t.column “client_id”, :integer
t.column “date”, :date
t.column “time”, :string
t.column “duration”, :integer
t.column “appointment_book_id”, :integer
t.column “description”, :text
end

Frederick C. wrote:

What does the (:db) to?
ActiveSupport overrides Date#to_s, passing :db makes it format the
string in the way the database wants it.

Sweet. I didn’t know that; thanks, Fred. :slight_smile:

Rick Denatale wrote:

(date…date + look_ahead).class # Range
(date…date + look_ahead).respond_to? :each # true

Sorry I missed the two dots.

No problem. We’re programmers; we miss things everyday. At least I do!

You said it was the line with the yield which is raising the
exception, but there’s no each there.

Others are looking at the find_all_by date, but what about the block
you are yielding to? What’s in that block?

It’s not the block. I’ve removed everything from that method (including
simplifying the caller of the method to exclude passing a block) except
the find_all_by_xxx and it still errors out.

On 10/7/07, Daniel W. [email protected] wrote:

True, Dates are not enumerable, but ranges are, and they respond to
each:

(date…date + look_ahead).class # Range
(date…date + look_ahead).respond_to? :each # true

Sorry I missed the two dots.

You said it was the line with the yield which is raising the
exception, but there’s no each there.

So…

It would seem to be something called by that line.

Others are looking at the find_all_by date, but what about the block
you are yielding to? What’s in that block?

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 10/7/07, Daniel W. [email protected] wrote:

You said it was the line with the yield which is raising the
exception, but there’s no each there.

Others are looking at the find_all_by date, but what about the block
you are yielding to? What’s in that block?

It’s not the block. I’ve removed everything from that method (including
simplifying the caller of the method to exclude passing a block) except
the find_all_by_xxx and it still errors out.

So what line in what file is actually suffering the method missing?
Seems to be time to take advantage of the fact that ActiveRecord and
the rest of Rails is open source.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/