Forum: Ruby on Rails Inconsitencies between find() and count() in ActiveRecord

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
0e577200992b9f87fbfdb84f70ae2cea?d=identicon&s=25 sirdavidoff <davewroberts@yahoo.com> (Guest)
on 2005-12-05 12:07
Hi guys,

I'm trying to do something that I imagine is quite common: implementing
a search for a particular record in a table (or ActiveRecord of Model).
In order to display the search results properly, I call count() to count
the number of search results before I do the actual search using find().
And this is where the problem is.

Sometimes I want to search using criteria that are in linked tables, e.g
I might have 2 tables, 'book' and 'author', and I want to find all the
books by a certain author. This is easy with find(); I can just put the
author table in the :include parameter. On the other hand, for count() I
must provide a fragment of SQL for the 'joins' parameter. Obviously
find() does this internally, generating the required SQL code from
:include. It seems to me that this in an inconsitency between the two
functions.

My question is, what is the function that find() calls to do this and
can I call it myself?

Maybe there is an easier way to implement this search functionality
using functions that I don't know about. But in my opinion, shouldn't
count() be exactly like find(:all) except it contains 'SELECT count(*)
FROM' instead of 'SELECT * FROM'?

David.
Dcc2d3a8038cd47219af0eebe0a8a78e?d=identicon&s=25 carl.fyffe (Guest)
on 2005-12-05 13:43
(Received via mailing list)
David,

These docs were pretty helpful:

http://rails.rubyonrails.com/classes/ActiveRecord/...

Carl
0e577200992b9f87fbfdb84f70ae2cea?d=identicon&s=25 sirdavidoff <davewroberts@yahoo.com> <davewroberts (Guest)
on 2005-12-05 13:50
Hi Carl, thanks for replying.

I have indeed looked at the Rails API documentation, but the source code
included only shows one level of functions. What I mean is that
according to the API, for a find(:all) with an :include parameter, a
function called find_with_associations() is called. However I don't know
what that function does because it is not part of the API.

I assume that it calls some function like generate_join_sql(:include).
How can I find this out?
9ab183bb240ffd3a3966d5a615b4bdeb?d=identicon&s=25 phil.ross (Guest)
on 2005-12-05 13:59
(Received via mailing list)
sirdavidoff <davewroberts@yahoo.com> wrote:
> must provide a fragment of SQL for the 'joins' parameter. Obviously
> find() does this internally, generating the required SQL code from
> :include. It seems to me that this in an inconsitency between the two
> functions.

I submitted a bug relating to this issue a month ago:

http://dev.rubyonrails.org/ticket/2760

Phil
0e577200992b9f87fbfdb84f70ae2cea?d=identicon&s=25 sirdavidoff <davewroberts@yahoo.com> <davewroberts (Guest)
on 2005-12-05 14:06
Hi Phil,

Good to know. In the meantime (before they get around fixing it), do you
know of a function to generate join sql fragments from table names, or
did you have to write one yourself? I thought it might get a bit
complicated when there are has_and_belongs_to_many associations
involved...

David.
2dd904ec5981c31e7bb7a5743a53caf8?d=identicon&s=25 Bruce Balmer (brucebalmer)
on 2005-12-05 15:09
(Received via mailing list)
If you are bringing the records down the pipe anyway (I think you
are, from what you wrote) then why not just use array.size as in:

@x = Model.find(:all, :conditions=>'blah blah blah')
count = @x.size

bruce
0e577200992b9f87fbfdb84f70ae2cea?d=identicon&s=25 sirdavidoff <davewroberts@yahoo.com> <davewroberts (Guest)
on 2005-12-05 15:22
No, the database I am using contains thousands of records so it wouldn't
be a good idea to actually retrieve all search results. Therefore what I
do is count how many results I have and then retrieve them in groups of
10 according to pagination...
51b840b74eacc1c32e31bfe412d542af?d=identicon&s=25 Sebastian Delmont (sdelmont)
on 2005-12-05 16:23
(Received via mailing list)
@pages, @records = paginate :records, :per_page => 10, ...


@pages.item_count #  => 237
@pages.page_count  # => 24
@records.size   # => 10


RTFM: http://api.rubyonrails.com/classes/ActionControlle...
Paginator.html
0e577200992b9f87fbfdb84f70ae2cea?d=identicon&s=25 sirdavidoff <davewroberts@yahoo.com> <davewroberts (Guest)
on 2005-12-05 16:35
Yeah, but in using pagination with a search I'd still be retrieving ALL
the search results from the database, wouldn't I?
B6e90ad1e69d563f1f13cccffe137262?d=identicon&s=25 Simon.Santoro (Guest)
on 2005-12-05 23:00
(Received via mailing list)
sirdavidoff <davewroberts@yahoo.com> <davewroberts wrote:
> Yeah, but in using pagination with a search I'd still be retrieving ALL
> the search results from the database, wouldn't I?

no.
893776896abed8a207a457286dee1130?d=identicon&s=25 Kenny Grant (kenny)
on 2005-12-06 13:54
sdelmont wrote:
> @pages, @records = paginate :records, :per_page => 10, ...
> @pages.item_count #  => 237
> @pages.page_count  # => 24
> @records.size   # => 10
>
> RTFM: http://api.rubyonrails.com/classes/ActionControlle...
> Paginator.html

Hi,

I read the f****** manual, and had a look at the source a while ago as I
ran into this problem. Paginate calls paginator_and_collection_for with
your collection and options. Unfortunately it then discards any :include
when passing to the count method as that won't accept them anyway, it
just takes conditions and joins. It doesn't seem very helpful to list
includes as accepted in this case.

The documentation for paginate claims the include option is passed to
model.count, however model.count doesn't accept includes, and I can't
see how it is passed in the source that I have.

>:include:	optional eager loading parameter passed to Model.find(:all, *params) and 
Model.count

So far as I can see this means the include parameter doesn't work with
paginate just now (Rails 0.14.3) if you need to refer to other tables in
your conditions statement, as the count won't accept the conditions with
foreign references. You have to use joins. If I'm wrong, please do let
us know how to use this properly.

From pagination.rb in ActionPack, line 185 :

 def paginator_and_collection_for(collection_id, options) #:nodoc:
      klass = options[:class_name].constantize
      page  = @params[options[:parameter]]
      count = count_collection_for_pagination(klass,
options[:conditions],
                                              options[:join] ||
options[:joins])

      paginator = Paginator.new(self, count, options[:per_page], page)
      collection = find_collection_for_pagination(klass, options,
paginator)

      return paginator, collection
    end
754e1c849101a2b96e441e7b897abc37?d=identicon&s=25 Jeremy Hopple (Guest)
on 2005-12-12 20:01
(Received via mailing list)
There is a new plugin that enhances Model.count so that it is
consitent Model.find...

Counting and limiting with named associations --
http://wiki.rubyonrails.com/rails/pages/Plugins#countlimit
This topic is locked and can not be replied to.