为具有类似数据类型的两个模型烘干代码

时间:2009-11-24 18:30:10

标签: ruby-on-rails ruby

假设我有一个葡萄酒和啤酒模型/控制器以及wine_review和beer_review模型,它们有许多关系。

每个表都有几乎相同的数据类型,例如wine_review和beer_review都有一个评级和评论列。 葡萄酒和啤酒各有名。

如何干掉我的代码,以便他们可以共享相同的视图。

现在我有两种观点做同样的事情,一次是啤酒,一次是葡萄酒。

<% @wine_reviews.each do |review| -%>
  <ul>
    <li><%= link_to review.wine.name, review.wine %></li>
    <li><%= review.rating %></li>
    <li><%=h review.comment %></li>
  </ul>
<% end -%>

<% @beer_reviews.each do |review| -%>
  <ul>
  ....
  ....

我真正想做的是像

<li><%= link_to review.beverage.name, review.beverage %></li>

根据我当时所呈现的情况,饮料会被葡萄酒或啤酒取代,但我无法弄清楚如何做到这一点。

我无法将饮料当作局部传递给部分,因为review.beverge会破坏。

感谢。

3 个答案:

答案 0 :(得分:6)

您有几种不同的选择:

鸭子打字:

在Ruby中,只要一个对象响应方法调用该方法就可以调用work。因此,如果啤酒和葡萄酒都有一个属性:name,那么调用@ result.name将适用于任何一种模型。

多态关联:

而不是rev​​iew.beer或review.wine。通过多态关联使葡萄酒和啤酒可审阅。这也适用于评论,例如,两者都可以评论。看看acts_as_commentable是如何工作的。 Railscasts的工作原理excellent screencast

单表继承:

您可以创建一个名为Beverage的对象,Wine和Beer继承该对象。这允许一个地方放置相似的属性,但仍然允许小的差异。

根据您的描述,您正在考虑这三者的组合。

答案 1 :(得分:1)

假设评论没有葡萄酒和啤酒的评论,您可以尝试将其添加到您的评论模型中。这可能不是确切的代码,但关键是在您的模型中,您会发现它的评论类型和您的观点并不关心。

def beverage
  @beverage ||= self.beer || self.wine
end

答案 2 :(得分:1)

多态关联就是答案。您可以设计包含以下内容的评论表:

create_table :beverage_reviews, :force => true do |t|
  t.string :review_text
  t.integer :rating
  t.string  :beverage_type
  t.string  :beverage_id
end

BeverageReview模型可以是:

class BeverageReview < ActiveRecord::Base
  belongs_to :beverage, :polymorphic => true
end

BeerWine模型可以是:

class Beer < ActiveRecord::Base
  has_one :beverage_review, :as => :beverage
end

这样,如果您要显示所有评论,您可以将代码编写为:

<% @all_reviews.each do |review| -%>
  <%= review.review_text -%>
  <%= review.beverage.name -%>
<% end -%>
相关问题