1

更新

好的,我想通了。我不得不调用以下品种:

<%=h @user.varieties.find_by_product_id(product.id).name %>

这是我的两个后续问题:

(1)这是否会因为我没有调用连接模型而在编辑/删除记录时引起问题?我看过一些 Ryan Bates 视频,他强调了这一点,但我在尝试在这里引用连接模型时遇到了麻烦。换句话说,是否应该通过调用上述代码user_products

如果我使用以下引用连接表的代码,我只能让它显示variety_id连接表中的 (因为连接表中没有品种的名称列)。我不确定如何让这段代码引用variety_id连接表中的 ,然后转到品种表以从“名称”列中获取品种的实际名称。

<% @user.products.each do |product| %>
   <% @user.user_products.find_by_product_id(product.id).variety_id %>
<% end %> 

(2)这个复杂的东西是否正确放置在视图层中,或者有没有更好的方法将其移动到模型或控制器中?

谢谢。

下面的原始问题现已解决...

我有以下模型:
- 用户
- 产品
- 品种 - user_products

这是我正在尝试做的真实世界版本。假设用户是一家杂货店。产品是水果,如苹果。品种是苹果的类型,如富士和麦金托什。

我需要创建一个应用程序,其中:

  • 用户可以将多种类型的产品添加到他的页面。产品可以包含多个品种,但用户不需要包含任何品种。例如,Topps Grocery Store 可以将苹果添加到他们的页面。如果这就是他们想要展示的全部内容,那应该没问题。但是,他们也可以通过包括他们携带的苹果类型来添加更多细节,如富士、麦金托什等。品种不能只是一个详细的产品。换句话说,我不能让每个产品都像苹果-富士,苹果-麦金托什。它们需要是两个独立的模型。

  • 在用户页面(即“显示”视图)上,我需要能够同时显示产品和品种(如果有)。系统需要了解品种与该特定用户的特定产品相关联。

根据我收到的第一个答案,我修改了我的模型,如下面的答案所述。每个品种属于一个产品,即fuji只属于苹果产品,在产品表中是一个不同的id。而且,一个产品有很多品种,即苹果产品可能有5到10个不同的品种。

然而,它变得更加复杂,因为每个用户可能有一组不同的产品/品种组合。例如,Topps 杂货店(用户)可能有 fuji 和 mcintosh(品种)的苹果(产品)。但是,Publix 杂货店(用户)可能有红色美味的苹果(产品)和嘎拉(品种)。

在用户页面上,如果用户选择了任何品种,我希望能够调用用户携带的每个产品,然后显示与每个产品相关的品种。

当我在显示视图中尝试下面列出的代码时,我收到以下错误:undefined method `user_product' for #:

<% @user.products.each do |product| %>
   <% @user.user_products.find_by_product_id(product.id).varieties %>
<% end %>

另一方面,当我尝试您给我的另一个选项(如下所列)时,页面加载并且 sql 查询在日志中似乎正确,但页面上没有显示任何品种,这很奇怪,因为我三重检查并且有数据库中应该匹配查询的记录。详情如下...

<% @user.products.each do |product| %>
   <% @user.varieties.find_by_product_id(product.id) %>
<% end %>    

此代码运行以下 sql 查询:

User Load (0.7ms) SELECT * FROM "users" WHERE ("users"."id" = 2)

Variety Load (0.5ms) SELECT "varieties".* FROM "varieties" INNER JOIN "user_product" ON "varieties".id = "user_products".variety_id WHERE (("seasons".user_id = 2))

在布局/应用程序中渲染模板
渲染用户/显示

Product Load (0.7ms) SELECT "products".* FROM "products" INNER JOIN "user_product" ON "products".id = "user_products".product_id WHERE (("user_products".user_id = 2))

Variety Load (0.4ms) SELECT "varieties".* FROM "varieties" INNER JOIN "user_product" ON "varieties".id = "user_products".variety_id WHERE ("varieties"."product_id" = 1) AND (("user_products".user_id = 2)) LIMIT 1

Variety Load (0.2ms) SELECT "varieties".* FROM "varieties" INNER JOIN "user_products" ON "varieties".id = "user_products".variety_id WHERE ("varieties"."product_id" = 2) AND (("user_products".user_id = 2)) LIMIT 1

在上面的这种情况下,我正在查看的用户是user_id=2, he does have product_id=1 and product_id=2 in the database. And, in the user_products table, I do have a few records that list this user_id connected to each of these product_ids and associated with some variety_ids. 所以看起来我应该在我的显示视图上显示一些结果,但我什么也没得到。

最后,当我尝试以下操作时:

<% @user.products.each do |product| %>
   <%=h @user.user_products.find_by_product_id(product.id) %>
<% end %>

它在我的视图中为每条记录显示以下内容:#<User_product:0x4211bb0>

4

2 回答 2

0

我认为他们的方式是您与产品没有多对多的关系。您拥有该特定品种的产品(如果有的话)。所以为了跟踪它,我会使用一个额外的模型。这样,您也可以保持产品和品种之间的关系。

型号:

class User < ActiveRecord::Base
  has_many :user_products, :dependent => :destroy
  has_many :products, :through => :user_products
  has_many :varieties, :through => :user_products
end

class UserProduct < ActiveRecord::Base
  belongs_to :user
  belongs_to :product
  belongs_to :variety
end

class Product < ActiveRecord::Base
  has_many :varieties
end

class Variety < ActiveRecord::Base
  belongs_to :product
end

控制器:

class UserProductsController < ApplicationController
    before_filter do 
        @user = User.find(params['user_id'])
    end


    def create
      product = Product.find(params['product_id'])
      variety = Variety.find(params['variety_id']) if params['variety_id']

      @user_product = UserProduct.new
      @user_product.user = user
      @user_product.product = product
      @user_product.variety = variety
      @user_product.save
    end

    def destroy
        # Either do something like this:
        conditions = {:user_id => @user.id}
        conditions[:product_id] = params[:product_id] if params[:product_id]
        conditions[:variety_id] = params[:variety_id] if params[:variety_id]

        UserProduct.destroy_all conditions
    end
end

观点:如果您对将品种分组到不同的产品不感兴趣,只需将它们作为列表列出,那么以下内容就足够了:

# users/show.html.erb
<%= render @user.user_products %>

# user_products/_user_product.html.erb
<%= h user_product.product.name %> 
<%= h user_product.variety.name if user_product.variety %>

否则必须添加一些更复杂的东西。其中一些可能可以通过使用关联代理来放入模型和控制器,但我无法帮助你

# users/show
<% for product in @user.products do %>
    <%= product.name %>
    <%= render :partial => 'variety', 
        :collection => @user.varieties.find_by_product_id(product.id) %>
<% end %>

# users/_variety
<%= variety.name %> 

将其分成部分当然是不必要的(在这个例子中,可能有点荒谬),但它有助于分离不同的部分,特别是如果你想添加更多的东西来显示。

并回答您的问题:

  1. 由于 UserProduct 是一个连接模型,因此您实际上不需要跟踪它的个人 ID。您拥有用户、产品和品种(在这些情况下它存在)。这就是您所需要的,该组合是唯一的,因此您可以找到要删除的记录。此外,永远不应该编辑连接模型(前提是您在其中没有比这些字段更多的属性),它可以创建或删除,因为它所做的只是保持关联。
  2. 因为它基本上是一个查看的东西,所以最好将它放在视图中。您当然可以使用控制器或模型预先收集所有产品和品种,方法如下:

将所有逻辑移至控制器和模型可能不是一个好主意,因为它们不应该知道(或关心)您希望如何显示数据。所以这只是准备充分的问题。

@products_for_user = []
@user.products.each do |product|
 collected_product = {:product => product, 
                      :varieties => @user.varieties.find_by_product_id(product.id)}
  @products_for_user << collected_product
end
于 2009-09-18T11:37:21.737 回答
0

迈克

您可能只是这里有一个错字,@user.user_product应该是@user.user_products

当我在显示视图中尝试下面列出的代码时,我收到以下错误:undefined method `user_product' for #:

<% @user.products.each do |product| %>  
  <% @user.user_product.find_by_product_id(product.id).varieties %>  
<% end %>

您也可以考虑一个分层类型系统,其中只有“Fuji”、“Macintosh”和“Apples”之类的产品。

然后,“Fuji”和“Macintosh”将有一列“parent_id”设置为“Apples”的 id。

只是一个想法。

于 2009-09-19T08:33:47.800 回答