【问题标题】:Rails: setting association object vs. setting association idRails:设置关联对象与设置关联 ID
【发布时间】:2013-05-21 00:20:01
【问题描述】:

我正在关注“使用 Rails 进行敏捷 Web 开发”一书,并尝试将产品价格复制到 LineItem。覆盖 LineItem 上的设置器似乎是合适的选择。然而,正如在 Rails 中经常发生的那样,生成两个 setter 使练习变得不简单:

  def product_id=(product_id)
    product = Product.find(product_id)
    write_attribute(:price, product.price)
    write_attribute(:product_id, product_id)
  end

  def product=(product)
    self.product_id = product.id #wtf? why isn't this the default?
  end

无论我设置对象还是它的 id,此代码都按预期工作,在这两种情况下,价格都会被复制。是什么让我想知道:

为什么这个委托在不覆盖“product=(..)”的情况下不能工作?奇怪的是,如果不删除“self”,它将无法正常工作,显然它不会委托给“product_id=()”...

【问题讨论】:

  • 通过将“product_id=”委托给“product=”而不是反之,对我的示例进行了明显的优化。这样,如果产品已经传递到 'product=' 中,则不必再次加载产品。

标签: ruby-on-rails rails-activerecord


【解决方案1】:

使用默认实现调用product= 不会调用product_id=。它只是使用write_attribute,就像您在覆盖的product_id= 方法中所做的那样。

【讨论】:

  • 赞成回答我的问题,反对 Rails 打破它自己的教条。如果他们连简单的代表都没有,DRY 怎么办?
  • 我不会将此归咎于 Rails/ActiveRecord。您真正需要的是 product_id 属性的观察者,AFAIK 没有提供开箱即用的属性。
  • 我假设这完全发生在 line_item 类内部,因此 line item 内部的回调可以做到。无论如何,考虑到一个潜在的测试用例,这不会导致我期望的行为——我基本上必须在价格属性更新之前保存记录。恕我直言,这是一个场景设置器的目的 - 允许一个挂钩来实现与属性更改相关的代码,所以我希望在我设置产品后价格会直接改变。
【解决方案2】:

你的模型不是最优的

我不太确定你想要做什么,或者你为什么要这么做,但在我看来,你的问题至少有一部分是你的模型关系是错误的——或者至少是次优。

这样看:

  1. 产品应该有价格。这在逻辑上是产品的属性。
  2. LineItem 实际上是产品及其属性的表示,可能还有其他一些相关数据。

我知道您正在学习一些教程,所以也许该教程试图提出一些具体的观点。但是,在现实世界的应用程序中,规范化的数据库不应该从模型到模型或对象到对象复制数据。价格应该只有一个住处,并且应该从其他表中引用(而不是复制)。

模型注意事项

如果您听从我的建议,那么 Product 有一个 ID,LineItem 具有对存储在 product_id 字段中的产品的引用,并且您可以通过 LineItem.product.price 访问价格,或者如果您不这样做,请设置委托对于这个常见的用例,不想违反得墨忒耳定律。

这可能对您的教程没有帮助,但对我来说,使用 ActiveRecord 关系肯定比将值从一个表复制到另一个表更有意义。 YMMV。

【讨论】:

  • 从数据库设计的角度来看,您是正确的,但实际上行项目反映了客户订单的一部分以及客户订购时的价格。考虑一下在客户订购产品和商店发送账单之间有人提高价格之间的愤怒。
  • @joerx 您当然还有其他选择:以当前价格存储当前购物车,将价格存储在会话中,使用观察者修改其他模型,等等。由于您没有发布其余的上下文,因此不得不假设您正在让其他模型了解产品内部结构;这通常是一个坏主意,但是 YMMV。祝你好运!
  • 1. - 因为什么时候使用公共属性意味着了解内部?这就是为什么它是公开的——供其他人使用。 2. - 如果我们可以让事情变得复杂,为什么要做一些简单的事情? - 我看不到会话或观察者如何帮助我解决问题。我想要一个购物篮作为客户订单的持久且历史一致的记录,以及一些刻意的非规范化(甚至可以争论)就可以简单而漂亮地做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-23
  • 2012-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-21
  • 1970-01-01
相关资源
最近更新 更多