【问题标题】:Multiple views of the same model同一模型的多个视图
【发布时间】:2012-06-18 03:27:33
【问题描述】:

我是一位经验丰富的 Web 开发人员,但对 Rails 很陌生。我正在编写基于复式记帐数据库的预算应用程序。数据库包含表示交易的日记帐分录,每个日记帐分录有多个过帐。每个帖子都有一个帐户和一个金额。

这是我的模型的简化版本:

class Posting < ActiveRecord::Base
  belongs_to :account
  belongs_to :journal_entry

  attr_accessible :account_id, :amount
end

class JournalEntry < ActiveRecord::Base
  has_many :postings, :dependent => :destroy

  attr_accessible :narrative, :posting_date, :postings_attributes

  accepts_nested_attributes_for :postings, :allow_destroy => :true,
    :reject_if => proc { |attrs| attrs.all? { |k, v| k == '_destroy' or v.blank? } } 
end

我已经成功创建了一个嵌套表单,它允许一起编辑日记帐分录及其过帐列表。但是,大多数日记帐分录都很简单,只有一个贷记分录和一个借记分录。在这种情况下,为了使数据输入更容易,我想要另一个表单,允许用户指定贷方账户、借方账户和金额。

根据我的研究,可以看到两种方法:

  1. 单表继承,其中 SimpleJournalEntry(扩展 JournalEntry)
  2. 使用 ActiveModel 制作不直接附加到数据库的 SimpleJournalEntry 模型,并在控制器中自己处理数据库更改

SimpleJournalEntry 模型将具有贷方账户、借方账户和金额,并将用于编辑简单记录。现有的 JournalEntry 模型仍将存在,以允许编辑更复杂的记录。

处理这种事情的“rails 方式”是什么?还有其他我没有考虑过的选择吗?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    在这一点上我不得不不同意 railsdog。我认为你确实有一个很好的 STI 候选人。特别是,我认为“让 [JournalEntry] 处理简单或复杂保存的细节”表明您正在处理两个独立的问题。

    如果您的简单和复杂的 JournalEntries 具有不同的业务逻辑,它们应该由两个不同的类来表示。不难想象,例如,复杂的 JournalEntry 可能想要添加简单的 JournalEntry 没有的验证。或者简单的 JournalEntry 应该比复杂的 JournalEntry 有更少的 attr_accessible 声明。我建议:

    class JournalEntry < ActiveRecord::Base
      # shared accessors and validations
    end
    
    class SimpleJournalEntry < JournalEntry
      # simple accessors and validations 
    end
    
    class ComplexJournalEntry < JournalEntry
      # more complex accessors and validations
    end
    

    我将使用单独的控制器和视图来处理这两个类。

    在一个不相关的注释中,#accepts_nested_attributes_for 的 :all_blank 选项应该做你的 Proc 所做的事情,不是吗?来自文档:“传递 :all_blank 而不是 Proc 将创建一个 proc,它将拒绝所有属性为空的记录,不包括 _destroy 的任何值。”即accepts_nested_attributes_for :postings, :reject_if =&gt; :all_blank

    【讨论】:

    • 感谢 :all_blank 的提示 - 我一定在文档中错过了这一点。我倾向于 STI,但我不确定将 has_many :postings 放在哪里。那应该在基础 JournalEntry 上,然后我在 SimpleJournalEntry 上为credit_postingdebit_posting 创建虚拟属性?
    • 我最终选择了 STI 方法。我将has_many :postings 放在JournalEntry 类的基础上。我必须在此关联上启用:autosave,因为我在 SimpleJournalEntry 模型中手动创建 Postings(基于 credit_account、debit_account 和 amount 的虚拟属性)。
    【解决方案2】:

    我不会使用 STI 来处理这个问题。本质上你有一个简单的“视图”和一个“复杂”的视图,底层模型没有改变,只是你想要呈现的视图。

    为这个简单视图创建备用链接(路径/路由)并在控制器中管理保存操作中的“简单性”并没有错,您只需检查收到的参数并决定要执行哪个操作拿走。

    更好的是,将收到的参数传递给您的日记账分录模型,让它处理简单或复杂保存的细节。毕竟,与会计相关的业务规则应该在模型中,不是吗?

    【讨论】:

    • 如何在日记账分录模型中处理这个问题?目前,我打电话给@journal_entry.update_attributes(params[:journal_entry]),ActiveModel 魔术会为我设置日记帐分录和过帐模型上的字段。
    • 我在下面阅读了 Ben 的回复(同样有效 - 欢迎来到 'tomayto' / 'tomahto' 的世界)。最简单的方法可能是检查参数以查看是否存在 simpleCreditAcct、simpleDebitAcct 和 simpleAmount,如果存在,则制作适当的两个过帐,将它们注入参数中,就好像它们来自复杂表单一样,并删除 simpleXXX 参数值.模型逻辑就是模型逻辑。尝试和测试这两种解决方案似乎都很昂贵。关键是找到适合您的可理解性和维护性。
    • 我尝试了这两种方法,STI 方法似乎更容易理解。感谢您的帮助。
    猜你喜欢
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    相关资源
    最近更新 更多