From: zdennis Date: 2006-08-29T11:28:27+09:00 Subject: Re: ActiveRecord, has_many and _count ... -----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 > > 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? 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. > > 3) 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 iD8DBQFE86bfMyx0fW1d8G0RAukPAJ9h4COcF11Zrzo0AVqjV1t8Il1hjACfcbuQ 7Qqh6h2BI4zt9P8WjMq59cg= =Nz8h -----END PGP SIGNATURE-----