2010-02-26 109 views
1

嗨:我正在用rails查询工作。最后,我想对以下内容做出JSON响应:所有国家的列表,包括至少一个公司,通过“地址”关联并计算一个国家有多少家公司。 这里是我的简单的模型结构:用Ruby on Rails进行查询

class Country < ActiveRecord::Base 
    has_many :addresses 
end 

class Address < ActiveRecord::Base 
    belongs_to :country 
    belongs_to :company 
end 

class Company < ActiveRecord::Base 
    has_one :address 
end 

什么是使用Rails来解决这个最优雅的方式?

+0

你已经试过了什么?到目前为止显示你的代码尝试,你会得到更好的回应。 – Timothy 2010-02-26 10:48:47

回答

1

你需要重载to_json方法:

class Country < ActiveRecord::Base 
    has_many :addresses 
    def to_json 
     # format your country as json with all the elements you need 
    end 
end 

然后在你的控制器做这样的事情:

countries = Country.find(:all).select{|c| c.companies.size > 0 } 
json = countries.collect{|c| c.to_json } 

你将不得不使用的has_many throught从国家获得公司。文档在这里:http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

对不起,我没有时间更精确的解决方案,但希望这些指针可以帮助你。如果您有特殊问题,请随时发表评论或打开一个新问题。

+0

谢谢!您的解决方案让我重新走上正轨! 在 “类国家<的ActiveRecord :: Base的” 我现在有: 高清to_json 哈希= { “国家名称”=> self.name, “量公司”=> self.companies.size} hash.to_json 结束 这似乎工作。 – Sney 2010-02-26 12:43:39

+0

如果你只是想要计数,你不应该使用c.companies.size,因为它会加载所有的记录(这很浪费)。改为使用c.companies.count。 – psyho 2010-02-26 13:56:06

+0

@Sney调用to_json方法'to_json'应该导致'循环' – 2012-02-24 16:03:04

1

您可能要添加计数器缓存到地址

belongs_to :country, :counter_cache => :companies_count 

它存储公司在国内的模式,从而节省您从N + 1查询问题的数量。

或者你可以避开它也通过发布这样一个查询:

Country.find(:all, :select => 'countries.*, count(addresses.id) as companies_count', :joins => 'LEFT JOIN addresses ON addresses.country_id = countries.id', :group => 'countries.id') 

这样,所有返回的国家将有一个包含公司的该国的数场companies_count。

+0

感谢您的提示! #1:我在Address中添加了“:counter_cache =>:companies_count”以及名为“companies_count”的列,但我仍然有n + 1个SQL查询。如何让计数器缓存最终运行? #2:通过发布单个SQL查询,我可以获得所有国家,即使是那些没有公司的国家。当我追加“:conditions =>'companies_count> 0'”我没有结果。有没有办法将这个限制添加到查询中,还是必须通过Ruby中的数组? – Sney 2010-02-26 15:09:59

+0

名为companies_count的列应该进入国家模式(国家/地区表)。您还需要记住它会自行设置它的初始值。你需要像Company.update_all('companies_count =(SELECT count(*)FROM addresses WHERE country_id = countries.id)')来设置正确的初始值。之后,你应该能够像你想要的那样查询国家。 – psyho 2010-02-27 21:34:58

+0

我将“Company.update_all ...”更改为“Country.update_all ...”。我还必须将“countries = Country.find(:all).select {| c | c.companies.count> 0}”改为“countries = Country.find(:all)”。选择{| C | c.companies_count> 0}“我认为rails会用”count“方法做一些魔术,但是看起来,我必须明确地调用只读属性”companies_count“。 – Sney 2010-02-27 22:40:22