2

我正在使用 2 个连接模型

class Product < ActiveRecord::Base
  has_and_belongs_to_many :providers
end
class Provider < ActiveRecord::Base
  has_and_belongs_to_many :products
end

我的控制器看起来像这样

class ProductsController < ApplicationController
    @products = Product.find( 
      :all, 
      :joins => :providers, 
      :select => "providers.id, providers.title, products.id, products.title, products.price", 
      :limit => 10)
    respond_to do |format|
      format.xml  { render :xml => @products }
      format.json { render :json => @products }
    end
  end
end

@products 未按预期呈现。XML 文件中仅显示 Product 模型的列。我尝试将 format.xml 行更改为

format.xml  { render :xml => @products.to_xml( :include => :providers) }

但这不是我想要的。您可以将我的 SQL 查询设为 5 列

SELECT providers.id, providers.title, products.id, products.title, products.price 
FROM `products` 
INNER JOIN `products_providers` ON `products_providers`.product_id = `products`.id 
INNER JOIN `providers` ON `providers`.id = `products_providers`.provider_id 
LIMIT 10

但在我的 XML 中只显示了 3 个。to_xml 方法还会生成一些外部 SQL 请求,我不希望这样。

有人可以向我提供有关如何告诉 rails 呈现我的所有 SQL 字段的信息吗?我也希望代码得到优化。

理想的 XML/JSON 设计应该是

<products type="array">
<product>
  <id type="integer">1</id>
  <price type="decimal">9.99</price>
  <title type="string">Sanke Rolex</title>
  <provider>
    <id type="string">1</id>
    <title type="string"></title>
  </provider>
</product>
</products>

谢谢!

4

2 回答 2

4

:select当您明确表示希望 XML 输出包含所有属性时,我不明白为什么您将自己限制在参数中的某些列。

最优化的代码是这样的:

@products = Product.all(:include => :providers, :limit => 10)
respond_to do |format|
  format.xml  { render :xml => @products.to_xml(:include => :providers) }
  format.json { render :json => @products.to_json(:include => :providers) }
end

我正在使用:include而不是:joins在 finder 中,这意味着 AR 将使用 2 个 SQL 查询来获取第一个产品,然后是提供程序,这对于更大的表来说比连接更快。

要在 XML 输出中排除某些私有列,请使用:except

@products.to_xml(
  :except => [:price],
  :include => { :providers => {:except => [:title]} }
)

你几乎总是想要这个,因为每个模型都包含不公开的信息。

于 2009-12-29T11:19:01.133 回答
1

在我想要一个非常具体的输出的情况下,我使用Builder 模板而不是 render :xml 快捷方式。这很简单。

于 2009-12-29T05:10:43.763 回答