# ActiveRecord, has\_many and \_count

**URL:** <https://www.ruby-forum.com/t/activerecord-has-many-and-count/66736>\
**Category:** Ruby\
**Created:** [August 28, 2006, 10:28pm UTC](https://www.ruby-forum.com/t/activerecord-has-many-and-count/66736 "2006-08-28T22:28:26Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![SSSSric\_DUMINIL](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3da27b/32.png) [@SSSSric\_DUMINIL](https://www.ruby-forum.com/u/SSSSric_DUMINIL)\
**Post date:** [August 28, 2006, 10:28pm UTC](https://www.ruby-forum.com/t/activerecord-has-many-and-count/66736/1 "2006-08-28T22:28:26Z")

</div>

Hi everybody!

Here are trunks of models from a little rails app I’m developing:

###########################  
class Country \< ActiveRecord::Base  
has\_many :companies  
…

###########################  
class Category \< ActiveRecord::Base  
has\_many :companies  
…

###########################  
class Company \< ActiveRecord::Base  
has\_many :employees , :dependent =\> true  
belongs\_to :country, :counter\_cache =\> true  
belongs\_to :category, :counter\_cache =\> true  
…

###########################

class Employee \< ActiveRecord::Base  
belongs\_to :company, :counter\_cache =\> true  
…

###########################

I just would like to know: The right way to create a new company by  
updating  
Country.find(id).companies.size is by doing  
Country.find(id).companies.create . Right?

1. But what if I’d like to keep in cache companies.size for the category  
in  
which the new company is put? I can’t create a company simultaneously  
using  
two parents!

2. When I edit the properties of a company, let’s say moving from Japan  
to  
Italy, how could I update Japan.companies\_count and  
Italy.companies\_count?  
I tried to modify the update action of CompanieController:

###########################

def update  
@company = Company.find(params[:id])  
@oldcountry=@company.country  
if @company.update\_attributes(params[:company])  
@newcountry=@company.country  
@oldcountry.companies\_count=@oldcountry.companies(:refresh).size  
@newcountry.companies\_count=@newcountry.companies(:refresh).size  
flash[:notice] = ‘Company was successfully updated.’  
redirect\_to :action =\> ‘show’, :id =\> @company  
else  
render :action =\> ‘edit’  
end  
end

###########################

but that did’nt work. ☹

1. Is there a Rails’ way to cache the number of Employees directly in  
Company.employees\_count and Category.employees\_count (i.e. through  
a “has\_many\_many” relation)? That would prevent iterating through every  
company of a given country/category to get its .employees\_count!

Thanks a lot for your attention,

Have a good night,

Eric

---

<div class="post-metadata">

**Author:** ![SSSSric\_DUMINIL](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3da27b/32.png) [@SSSSric\_DUMINIL](https://www.ruby-forum.com/u/SSSSric_DUMINIL)\
**Post date:** [August 29, 2006, 12:15am UTC](https://www.ruby-forum.com/t/activerecord-has-many-and-count/66736/2 "2006-08-29T00:15:02Z")

</div>

I think you want the Rails mailing list…

Max

---

<div class="post-metadata">

**Author:** ![SSSSric\_DUMINIL](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3da27b/32.png) [@SSSSric\_DUMINIL](https://www.ruby-forum.com/u/SSSSric_DUMINIL)\
**Post date:** [August 29, 2006, 4:29am UTC](https://www.ruby-forum.com/t/activerecord-has-many-and-count/66736/3 "2006-08-29T04:29:29Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

Éric DUMINIL wrote:

> I just would like to know: The right way to create a new company by updating  
> Country.find(id).companies.size is by doing  
> Country.find(id).companies.create . Right?

This is one way of doing it. Although if you have the id of the Country  
you can just say:  
company = Company.create( :company\_name=\>‘ABC Co’, :country\_id=\>1 )  
OR  
company = Company.new( :company\_name=\>‘ABC Co’, :country\_id=\>1 )  
company.save

Both of these will update the country countries\_counter because you have  
defined this in your belongs\_to relationship.

> 1. But what if I’d like to keep in cache companies.size for the category in  
> which the new company is put? I can’t create a company simultaneously using  
> two parents!

This can be solved using create or save on Company itself, rather then  
doing Country.find.companies.create. Since you have defined the  
belongs\_to relationship and specified the counter cache ActiveRecord  
will be smart enough to update both of them. The following example will  
work:  
Company.create :company\_name=\>‘ABC’, :country\_id=\>1, :category\_id=\>1

> 1. When I edit the properties of a company, let’s say moving from Japan to  
> Italy, how could I update Japan.companies\_count and Italy.companies\_count?

If you edit the properties of a company and save it ActiveRecord will  
correctly increment/decrement the counter cache fields that you have  
placed on your tables.

Using :refresh will ensure that you get the most recent data from the  
database.

> 1. Is there a Rails’ way to cache the number of Employees directly in  
> Company.employees\_count and Category.employees\_count (i.e. through  
> a “has\_many\_many” relation)? That would prevent iterating through every  
> company of a given country/category to get its .employees\_count!

I don’t know about the count via a another relationship, but you can  
always count them at once rather then iterating over each company.

Category.count(  
:joins=\>"INNER JOIN #{Company.table\_name} ON " +  
“#{Company.table\_name}.category\_id=” +  
“#{Category.table\_name}.id " +  
“INNER JOIN #{Employee.table\_name} ON " +  
“#{Employee.table\_name}.company\_id=#{Company.table\_name}.id”,  
:group=\>”#{Category.table\_name}.id” )

This will give you an array of arrays, where each internal array is  
employee\_count, category\_id:  
[[ 4, 1], [2, 2], [30, 3] ]

It doesn’t handle categories that do not have any employees although  
that could be fixed.

This is perhaps not as simple of a solution you’re looking for. Perhaps  
someone else knows if you can do counter\_cache using :through. 😉

Zach

-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)  
Comment: Using GnuPG with Mozilla - [http://enigmail.mozdev.org](http://enigmail.mozdev.org)

iD8DBQFE86bfMyx0fW1d8G0RAukPAJ9h4COcF11Zrzo0AVqjV1t8Il1hjACfcbuQ  
7Qqh6h2BI4zt9P8WjMq59cg=  
=Nz8h  
-----END PGP SIGNATURE-----

---

<div class="post-metadata">

**Author:** ![SSSSric\_DUMINIL](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3da27b/32.png) [@SSSSric\_DUMINIL](https://www.ruby-forum.com/u/SSSSric_DUMINIL)\
**Post date:** [August 29, 2006, 4:35am UTC](https://www.ruby-forum.com/t/activerecord-has-many-and-count/66736/4 "2006-08-29T04:35:29Z")

</div>

-----BEGIN PGP SIGNED MESSAGE-----  
Hash: SHA1

zdennis wrote:

> This is one way of doing it. Although if you have the id of the Country  
> you can just say:  
> company = Company.create( :company\_name=\>‘ABC Co’, :country\_id=\>1 )  
> OR  
> company = Company.new( :company\_name=\>‘ABC Co’, :country\_id=\>1 )  
> company.save
> 
> Both of these will update the country countries\_counter because you have  
> ^^^^^^^^^^^^^^^  
> should be companies\_counter. 😉

Zach  
-----BEGIN PGP SIGNATURE-----  
Version: GnuPG v1.4.2.2 (GNU/Linux)  
Comment: Using GnuPG with Mozilla - [http://enigmail.mozdev.org](http://enigmail.mozdev.org)

iD8DBQFE86hbMyx0fW1d8G0RAsWHAJ0XsQqlFXZePu0A+xXdsw3FRn4DfQCfUAyX  
xNpxNiX3RqhDAfutQC3Ud1k=  
=P1Yo  
-----END PGP SIGNATURE-----
