README.md in dase-4.1.1 vs README.md in dase-4.2.0
- old
+ new
@@ -1,109 +1,90 @@
[![Build Status](https://secure.travis-ci.org/vovayartsev/dase.png)](http://travis-ci.org/vovayartsev/dase)
## Overview
-Dase gem provides 'includes_count_of' method on a relation, which works similar to ActiveRecord's 'includes' method.
+Dase gem provides `includes_count_of` method on a relation, which works similar to ActiveRecord's `preload` method and solves [N+1 query problem](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) when counting records in `has_many` ActiveRecord associations.
-![Dase example](https://vovayartsev-home.s3.amazonaws.com/dase-mockup.png)
-
-Calling 'includes_count_of(:articles)' on a relation object adds 'articles_count' method to each of the authors:
-```
- authors = Author.includes(:publisher).includes_count_of(:articles, :conditions => {:year => 2012})
- authors.first.name # => 'Billy'
- authors.first.articles_count # => 2
-```
-
-
-## Installation
-
-Add this line to your Rails 3.2.x application's Gemfile:
-
- gem 'dase', "~> 3.2.4"
-
## Usage
-### Basic usage:
+Given this data in the DB:
+![Dase example](https://dl.dropboxusercontent.com/u/8560625/dase.png)
+and this Rails model definition
+```ruby
+class Author
+ has_many :articles
+end
```
- class Author
- has_many :articles
- end
-
- Author.includes_count_of(:articles).find_each do |author|
- puts "#{author.name} has #{author.articles_count} articles published"
- end
+you can now write this:
```
+ authors = Author.includes_count_of(:articles)
+ billy = authors.first # => #<Author name: 'Billy'>
+ billy.articles_count # => 2
+```
-### Using :conditions hash
-Specify a hash of options which will be passed to the underlying finder
-which retrieves the association. Valid keys are: :conditions, :group, :having, :joins, :include
+with conditions on associated records (only articles in year 2012)
```
-Author.includes_count_of(:articles, :conditions => {:year => 2012}) # counts only articles in year 2012
+ Author.includes_count_of(:articles, where: {year: 2012} )
```
-### Using scope merging
+using lambda syntax (in v4.1 and greater)
```
-class Article
- belongs_to :author
- scope this_year, lambda { where(:year => 2012) }
-end
+ Author.includes_count_of(:articles, -> { where(year: 2012) } )
+```
-results = Author.includes_count_of(:articles, :only => Article.this_year)
-results.first.articles_count # => # number of articles of given Author for year 2012 only
+with renamed counter method
```
-This is achieved by merging the association scope with the scope provided as ":only => ..." option.
-No additional checks are performed, and providing the association of proper type is solely your responsibility.
+ Author.includes_count_of(:articles, -> { where(year: 2012) }, as: :number_of_articles_in_2012)
+```
-
-### Renaming counter column
+with multiple associations counted at once
```
-sites = WebSite.includes_count_of(:users, :conditions => {:role => 'admin'}, :as => :admins_count)
-sites.each { |site| puts "Site #{site.url} has #{site.admins_count} admin users" }
+ Author.includes_count_of(:articles, :photos, :tweets)
```
-## Compatibility
+## Installation
-### Rails versions
+| Rails version | Add this to Gemfile |
+|---------------|------------------------|
+| 3.2.x | gem 'dase', '~> 3.2.0' |
+| 4.0.x | ----- N/A ----- |
+| 4.1.x | gem 'dase', '~> 4.1.0' |
+| 4.2.0.beta2 | gem 'dase', :github => 'vovayartsev/dase', :branch => 'rails-4-2' |
-This gem is for Rails 3.2.x . Earlier versions are not supported.
+## Under the hood
-Note: the Dase gem version number correlates with the Active Record's versions number,
-which it has been tested with.
-E.g. the latest 3.2.* version of Dase will play nicely with the latest 3.2.* version of Active Record.
-Since dase gem is a sort of a "hack", make sure you specified the version number for "dase" gem in your Gemfile.
-
-### Polymorphic associations and HasManyThrough associations
-
-Polymorphic associations and HasManyThrough associations support should work, but it is not tested quite well.
-Bug reports and pull requests are very welcome.
-
-### jRuby support
-
-Not yet
-
-## How it works
-
-Here's a pseudo-code that gives an idea on how it works internally
+When a relation is "materialized", we run a custom preloader which calculates the hash of counters in a single SQL query like this:
```
counters_hash = Article.where(:year => 2012).count(:group => :author_id)
- Author.find_each do |author|
- puts "#{author.name} has #{counters_hash[author.id] || 0} articles published"
- end
```
+then we add counters to the parent records like this:
+```
+ define_method(:articles_count) { counters_hash[author.id] || 0 }
+```
+## Alternative approaches
+Dase calculates counters dynamically every time you make an SQL query. It makes an extra SQL query for each association processed. These alternatives may be more efficient:
+* Cache column in the DB - see [counter_culture](https://github.com/magnusvk/counter_culture) gem, or [counter_cache](http://guides.rubyonrails.org/association_basics.html#counter_cache) in Rails Guides.
+* Using subquery in SELECT clause, or JOIN+SELECT+GROUP approach, as explained in [that video](http://www.youtube.com/watch?v=rJg3I-leoo4)
+
## Name origin
The gem is named by the german mathematician [Johann Dase](http://en.wikipedia.org/wiki/Zacharias_Dase),
-who was a mental calculator - he could count and multiply numbers very quickly.
+who was a [mental calculator](http://en.wikipedia.org/wiki/Mental_calculator) and could add and multiply numbers very quickly.
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
-[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/vovayartsev/dase/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+
+[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/vovayartsev/dase/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
+
+
+
+