undefined method for 1:Fixnum

Hi all,

What I am trying to do:

1) Search for books at a specific school
2) Iterate through each book and find all its related subbooks where
the book state is of a specific type
3) Return an array of those subbooks for each book
4) Since the array will have subarrays of the subbooks, flatten them
into one big array
5) then return the subbook with the lowest sequence number

What I did:

subbook = Subbook.get_for_assignment(site, :available_for_assignment)

def self.get_for_assignment(site,book_state)

    books = Book.where(:location_id => site, :location_type =>
'Site').all

    available_books = books.each.map do |book|
      book.subbooks.where(:book_state_id =>
BookState[:available_for_assignment].id)
    end

    raise ApplicationError, "Book out of order" unless
available_books.size > 0

    available_book = available_books.flatten.map(&:sequence).min
#available_books.flatten.first (temporary although inaccurate fix)
    if available_book.sequence > 100
      available_book.book.update_attributes! :book_state_id =>
BookState[:distributed].id
    end
    available_book
  end

The results:

"undefined method sequence for 1:Fixnum"

This line right here:

available_books.flatten.map(&:sequence).min

produces the above error. It's this part "map(&:sequence).min" that is
causing it. Basically I am flattening the array of subbooks and then
searching the one which has the lowest value for the sequence
attribute, corresponding to a sequence field in the subbooks table.

thanks for response

The problem is that the "array of subbooks" isn't an array of
subbooks, it's an array of something which includes some integers.
Hence, when you iterate it, you get an undefined method for Integer.

I would be inspecting the available_books array in debug (or the
console) and seeing what it really consists of.

BTW, I'd also suggest that the whole "get_for_assignment" method could
be achieved by a scope with the appropriate conditions...

Thanks for response. I checked with logger and it is indeed an array:

logger.info "Is array? #{available_books.flatten.is_a?(Array)}"
#outputs: true

It's an array of subbook objects:
<Subbook:0x10bef7de0>#<Subbook:0x10bef7ca0>#<Subbook:
0x10bef7bb0>#<Subbook:0x10bef7ae8>#<Subbook:0x10bec0ed0>#<Subbook:
0x10bec0db8>#<Subbook:0x10bec0cc8>#<Subbook:0x10bec0840>#<Subbook:
0x10bea9140>#<Subbook:0x10bea8fd8>#<Subbook:0x10bea8e70>#<Subbook:
0x10bea8c90>#<Subbook:0x10be8a998>#<Subbook:0x10be8a678>#<Subbook:
0x10be8a268>#<Subbook:0x10be86c80>#<Subbook:0x10be780e0>#<Subbook:
0x10be78018>#<Subbook:0x10be77f28>#<Subbook:0x10be77e88>#<Subbook:
0x10be69b58>#<Subbook:0x10be69ab8>#<Subbook:0x10be699a0>#<Subbook:
0x10be698d8>#<Subbook:0x10be63d98>#<Subbook:0x10be63cf8>#<Subbook:
0x10be63b90>#<Subbook:0x10be63af0>#<Subbook:0x10be5d3d0>#<Subbook:
0x10be5cd90>#<Subbook:0x10be5c4f8>#<Subbook:0x10be5c3e0>#<Subbook:
0x10be53768>#<Subbook:0x10be53420>#<Subbook:0x10be532e0>#<Subbook:
0x10be531f0>#<Subbook:0x10be46180>#<Subbook:0x10be45e88>#<Subbook:
0x10be45ac8>#<Subbook:0x10be45960>

Now when I look at above, it appears to reference the class itself,
and since Active Record converts fields to instance methods, the class
itself doesn't have access to the sequence instance method, only
instances of the class.

Is this the problem and how would I address it?

Thanks for response

hmmm, this returns true as well:

    logger.info "is true? #{available_books.flatten.first.respond_to?
('sequence')}"

This line right here:

available_books.flatten.map(&:sequence).min

produces the above error. It's this part "map(&:sequence).min" that is
causing it. Basically I am flattening the array of subbooks and then
searching the one which has the lowest value for the sequence
attribute, corresponding to a sequence field in the subbooks table.

I suspect the error is actually being raised on the next line where
you do

available_book.sequence > 100

since you've set available_book
to available_books.flatten.map(&:sequence).min, ie available_book is
the smallest sequence number

Fred

actually you are right. my intention was to get the object with the
smallest sequence number, not return the sequence number itself. The
ruby documentation says this: "Returns the object in enum with the
minimum value. " for min. Hence, I thought it would return the object.

actually you are right. my intention was to get the object with the
smallest sequence number, not return the sequence number itself. The
ruby documentation says this: "Returns the object in enum with the
minimum value. " for min. Hence, I thought it would return the object.

It depends what you are iterating over - because you first called
map(&:sequence) the enumerable in question was the array of sequence
numbers. If you want to get back the object with the smallest sequence
value you should drop the call to map and either use the block form of
min or min_by

Fred

Good catch, Fred.