1

请参阅问题底部的更新。

我不得不对我的应用程序进行一些调整以添加新功能,而我的更改似乎破坏了以前完美运行的 :uniq 选项。

这是设置:
#User.rb
has_many :products, :through => :seasons, :uniq => true
has_many :varieties, :through => :seasons, :uniq => true
has_many :seasons

#product.rb
has_many :seasons
has_many :users, :through => :seasons, :uniq => true
has_many :varieties

#season.rb
belongs_to :product
belongs_to :variety
belongs_to :user
named_scope :by_product_name, :joins => :product, :order => 'products.name'

#variety.rb
belongs_to :product
has_many :seasons
has_many :users, :through => :seasons, :uniq => true

首先,我想向您展示当前正在破坏的视图的先前版本,以便我们有一个基线进行比较。下面的视图是拉起属于用户的产品和品种。在以下两个版本中,我为用户分配了相同的产品/品种,因此日志将查看完全相同的用例。

#user/show

<% @user.products.each do |product| %>  
  <%= link_to product.name, product %>
    <% @user.varieties.find_all_by_product_id(product.id).each do |variety| %>
      <%=h variety.name.capitalize %></p>
<% end %>
<% end %>  

这行得通。它只显示一种产品,然后显示每种产品的品种。在下面的日志中,产品 ID 1 有 3 个关联品种。产品 ID 43 没有。

这是上面代码的日志输出:

Product Load (11.3ms)   SELECT DISTINCT `products`.* FROM `products` INNER JOIN `seasons` ON `products`.id = `seasons`.product_id WHERE ((`seasons`.user_id = 1)) ORDER BY name, products.name  

Product Columns (1.8ms)   SHOW FIELDS FROM `products`  
Variety Columns (1.9ms)   SHOW FIELDS FROM `varieties`  
Variety Load (0.7ms)   SELECT DISTINCT `varieties`.* FROM `varieties` INNER JOIN `seasons` ON `varieties`.id = `seasons`.variety_id WHERE (`varieties`.`product_id` = 1) AND ((`seasons`.user_id = 1)) ORDER BY name  
Variety Load (0.5ms)   SELECT DISTINCT `varieties`.* FROM `varieties` INNER JOIN `seasons` ON `varieties`.id = `seasons`.variety_id WHERE (`varieties`.`product_id` = 43) AND ((`seasons`.user_id = 1)) ORDER BY name

好的,所以上面的所有内容都是以前的版本,效果很好。在新版本中,我在名为 的连接表中添加了一些列seasons,并制作了一堆自定义方法来查询这些列。因此,我对您在上面看到的视图代码进行了以下更改,以便我可以访问seasons模型上的这些方法:

<% @user.seasons.by_product_name.each do |season| %>  
  <%= link_to season.product.name, season.product %>  
    #Note: I couldn't get this loop to work at all, so I settled for the following:
    #<% @user.varieties.find_all_by_product_id(product.id).each do |variety| %>
    <%=h season.variety.name.capitalize %>  
  <%end%>
<%end%>  

这是日志输出:

SQL (0.9ms)   SELECT count(DISTINCT "products".id) AS count_products_id FROM "products" INNER JOIN "seasons" ON "products".id = "seasons".product_id WHERE (("seasons".user_id = 1))  
Season Load (1.8ms)   SELECT "seasons".* FROM "seasons" INNER JOIN "products" ON "products".id = "seasons".product_id WHERE ("seasons".user_id = 1) AND ("seasons".user_id = 1) ORDER BY products.name  
Product Load (0.7ms)   SELECT * FROM "products" WHERE ("products"."id" = 43) ORDER BY products.name  
CACHE (0.0ms)   SELECT "seasons".* FROM "seasons" INNER JOIN "products" ON "products".id = "seasons".product_id WHERE ("seasons".user_id = 1) AND ("seasons".user_id = 1) ORDER BY products.name  
Product Load (0.4ms)   SELECT * FROM "products" WHERE ("products"."id" = 1) ORDER BY products.name  
Variety Load (0.4ms)   SELECT * FROM "varieties" WHERE ("varieties"."id" = 2) ORDER BY name  
CACHE (0.0ms)   SELECT * FROM "products" WHERE ("products"."id" = 1) ORDER BY products.name  
Variety Load (0.4ms)   SELECT * FROM "varieties" WHERE ("varieties"."id" = 8) ORDER BY name  
CACHE (0.0ms)   SELECT * FROM "products" WHERE ("products"."id" = 1) ORDER BY products.name  
Variety Load (0.4ms)   SELECT * FROM "varieties" WHERE ("varieties"."id" = 7) ORDER BY name  
CACHE (0.0ms)   SELECT * FROM "products" WHERE ("products"."id" = 43) ORDER BY products.name  
CACHE (0.0ms)   SELECT count(DISTINCT "products".id) AS count_products_id FROM "products" INNER JOIN "seasons" ON "products".id = "seasons".product_id WHERE (("seasons".user_id = 1))  
CACHE (0.0ms)   SELECT "seasons".* FROM "seasons" INNER JOIN "products" ON "products".id = "seasons".product_id WHERE ("seasons".user_id = 1) AND ("seasons".user_id = 1) ORDER BY products.name  
CACHE (0.0ms)   SELECT * FROM "products" WHERE ("products"."id" = 1) ORDER BY products.name  
CACHE (0.0ms)   SELECT * FROM "products" WHERE ("products"."id" = 1) ORDER BY products.name  
CACHE (0.0ms)   SELECT * FROM "varieties" WHERE ("varieties"."id" = 8) ORDER BY name

我有两个问题:
(1) :uniq 选项不适用于products. 同一产品的三个不同版本显示在页面上。
(2) :uniq 选项不适用于varieties. 我还没有对此设置验证,如果用户两次输入相同的品种,它确实会出现在页面上。在以前的工作版本中,情况并非如此。

我需要的结果是任何给定 ID 仅显示一个产品,并且与该 ID 关联的所有品种与此类唯一产品一起显示。

让我印象深刻的一件事是最近的日志输出中的 sql 调用。它将“计数”添加到不同的调用中。我不确定它为什么这样做,或者它是否可能表明存在问题。我发现这张未解决的灯塔票似乎可能相关,但我不确定它是否是同一个问题:https ://rails.lighthouseapp.com/projects/8994/tickets/2189-count-breaks-sqlite -has_many-through-association-collection-with-named-scope

更新

我认为问题在于named_scope 每个季节都被调用一次。named_scope 中需要有一些东西可以按季节 ID 缩小返回的产品范围。

现在发生的事情是:

user = get me user
seasons = get me user's seasons (say, there are 3 seasons for user)
products = get me the products
products += get me the products
products += get me the products

给我每一个产品

所以发生的事情不是 uniq 正在破坏,而是命名范围上没有分隔符。(我认为)。

我尝试了以下方法,但它抛出了这个异常:odd number list for Hash

named_scope :by_product_name, lambda { |seasons| { season_ids = seasons.map { |season| season.id }; :joins => :product, :conditions => { :seasons { :id => season_id } }  :order => 'products.name' } }  

想法?

更新#2

好的,现在我在想也许它根本不是命名范围。

#user/show中,我只是更改了循环以绕过命名范围:

<% @user.seasons.each do |season| %>  
  <%= link_to season.product.name, season.product %>  
    #Note: I couldn't get this loop to work at all, so I settled for the following:
    #<% @user.varieties.find_all_by_product_id(product.id).each do |variety| %>
    <%=h season.variety.name.capitalize %>  
  <%end%>
<%end%>    

上面没有使用命名范围,但我仍然得到相同的结果。换句话说,我仍然看到每个产品的所有实例,而不仅仅是一个。

上面创建第一个循环的代码与我在此问题顶部列出的原始代码相同。不同之处在于,这段代码循环通过seasons命中products,而我的原始代码循环通过products. 这种差异是问题所在,但我不知道如何解决它。

另外,我在最初的问题中提到我也无法让品种循环工作。您可以直接在上面的代码中看到注释的行。当循环遍历季节而不是产品时,当 Rails 遇到该品种循环时,它会引发名称错误:

undefined local variable or method `product'  

似乎这可能是同一问题的另一个症状?

还有其他想法吗?

4

1 回答 1

0

我认为问题在于 lambda 的格式。我显然无法运行 SQL,但以下 lambda 确实创建了一个适当的哈希:

lambda { |seasons| season_ids = seasons.map { |season| season.id }; { :joins => :product, :conditions => { :seasons => { :id => season_ids } }, :order => 'products.name' } }

该呼叫的输出有两个季节,ID 为 1 和 2:

{:joins=>:product, :conditions=>{:seasons=>{:id=>[1, 2]}}, :order=>"products.name"}
于 2010-03-15T14:47:55.180 回答