| 498 | | # Count operates using three different approaches. |
|---|
| 499 | | # |
|---|
| 500 | | # * Count all: By not passing any parameters to count, it will return a count of all the rows for the model. |
|---|
| 501 | | # * Count by conditions or joins: For backwards compatibility, you can pass in +conditions+ and +joins+ as individual parameters. |
|---|
| 502 | | # * Count using options will find the row count matched by the options used. |
|---|
| 503 | | # |
|---|
| 504 | | # The last approach, count using options, accepts an option hash as the only parameter. The options are: |
|---|
| 505 | | # |
|---|
| 506 | | # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. |
|---|
| 507 | | # * <tt>:joins</tt>: An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed). |
|---|
| 508 | | # The records will be returned read-only since they will have attributes that do not correspond to the table's columns. |
|---|
| 509 | | # * <tt>:include</tt>: Named associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer |
|---|
| 510 | | # to already defined associations. When using named associations count returns the number DISTINCT items for the model you're counting. |
|---|
| 511 | | # See eager loading under Associations. |
|---|
| 512 | | # |
|---|
| 513 | | # Examples for counting all: |
|---|
| 514 | | # Person.count # returns the total count of all people |
|---|
| 515 | | # |
|---|
| 516 | | # Examples for count by +conditions+ and +joins+ (for backwards compatibility): |
|---|
| 517 | | # Person.count("age > 26") # returns the number of people older than 26 |
|---|
| 518 | | # Person.find("age > 26 AND job.salary > 60000", "LEFT JOIN jobs on jobs.person_id = person.id") # returns the total number of rows matching the conditions and joins fetched by SELECT COUNT(*). |
|---|
| 519 | | # |
|---|
| 520 | | # Examples for count with options: |
|---|
| 521 | | # Person.count(:conditions => "age > 26") |
|---|
| 522 | | # Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job) # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN. |
|---|
| 523 | | # Person.count(:conditions => "age > 26 AND job.salary > 60000", :joins => "LEFT JOIN jobs on jobs.person_id = person.id") # finds the number of rows matching the conditions and joins. |
|---|
| 524 | | def count(*args) |
|---|
| 525 | | options = {} |
|---|
| 526 | | |
|---|
| 527 | | #For backwards compatibility, we need to handle both count(conditions=nil, joins=nil) or count(options={}). |
|---|
| 528 | | if args.size >= 0 and args.size <= 2 |
|---|
| 529 | | if args.first.is_a?(Hash) |
|---|
| 530 | | options = args.first |
|---|
| 531 | | #should we verify the options hash??? |
|---|
| 532 | | else |
|---|
| 533 | | #Handle legacy paramter options: def count(conditions=nil, joins=nil) |
|---|
| 534 | | options.merge!(:conditions => args[0]) if args.length > 0 |
|---|
| 535 | | options.merge!(:joins => args[1]) if args.length > 1 |
|---|
| 536 | | end |
|---|
| 537 | | else |
|---|
| 538 | | raise(ArgumentError, "Unexpected parameters passed to count(*args): expected either count(conditions=nil, joins=nil) or count(options={})") |
|---|
| 539 | | end |
|---|
| 540 | | |
|---|
| 541 | | options[:include] ? count_with_associations(options) : count_by_sql(construct_counter_sql(options)) |
|---|
| 542 | | end |
|---|
| 543 | | |
|---|
| 544 | | def construct_counter_sql(options) |
|---|
| 545 | | sql = "SELECT COUNT(" |
|---|
| 546 | | sql << "DISTINCT " if options[:distinct] |
|---|
| 547 | | sql << "#{options[:select] || "#{table_name}.#{primary_key}"}) FROM #{table_name} " |
|---|
| 548 | | sql << " #{options[:joins]} " if options[:joins] |
|---|
| 549 | | add_conditions!(sql, options[:conditions]) |
|---|
| 550 | | sql |
|---|
| 551 | | end |
|---|
| 552 | | |
|---|