具有许多属性的拆分模型

时间:2015-01-21 14:08:23

标签: ruby-on-rails ruby-on-rails-4

我的模型Foo包含许多属性(由PaperclipDevise和其他内容生成)。现在我的表有43列。

优点和缺点是:

  • +我尊重标准OOP。
  • -在数据库选择之后创建每个模型实例的时间更长。
  • - .inspect方法难以阅读(我认为不是最重要的,也很容易覆盖)。
  • -模型的源代码需要超过700行(可以使用Concern解决)

我的问题是,我不需要90%的网页上的所有论文信息。

我想到了一个解决方案,但需要一些专业知识才能知道这是一个好主意还是坏主意。

我们的想法是将模型切割成分为两部分:FooFooInfos,其中:

  • Foo包含所有主要信息
  • FooInfos包含10%剩余页面的所有信息,仅在必要时加载(使用delegate方法,例如。)
  • foo对象has_one foo_info

使用这种方法,上面提到的所有优点都会成为缺点,反之亦然。

这是个好主意吗?你有一些不这样的情况吗?你还有其他想法吗?

此致

1 个答案:

答案 0 :(得分:3)

正如您所描述的那样,您的模型Foo包含的信息太多了。

将信息移动到通用FooInfos类/表中只会掩盖间接背后的原始问题,而不是解决它。

指出正确的方向:询问"如何使这个模型更小"是第一步,但你需要问一个稍微不同的问题:

这门课完全是一件事吗?如果没有,我该如何区分问题?

这样做的一个变体是:"这个课程中隐藏着哪些不同的问题?"有多种方法可以将隐藏在单个页面对象中的信息和关注点分开。

一些工具:

  • 1)隔离信息
  • 2)将信息分成多个模型
  • 3)STI(单表继承)
  • 4)Mixins
  • 还有很多很多


1)隔离信息

分析您的代码并注意以下事项:一组方法正在使用一组属性并使用单独的视图元素。或者通常通过一组相关的接口方法在模型级别上访问。

每次你写一个(更大的)新功能时,问问自己这是否真的是一个直接属于当前模型的特征,或者它是否是它自己的模型(或者是一个辅助模型) )。

2)多个模型

你可以像你在问题中描述的那样拆分一些信息:引入另一个模型(比如FooInfo,但实际上不是就像这样!):

不要只提取一些元信息,但要让模型名称重要!

例如:

  • 可以将Paperclip内容提取到Attachment模型中,其中Page模型可以有一个或多个附件模型。
  • 设计访问权限内容可以通过CanCan
  • 进行管理
  • SidebarContent作为在侧栏内表示页面信息的方法
  • ...

我确定你会在你的Page对象中发现很多东西,实际上这是另一个问题。

您仍然可以通过部分呈现附加信息,并将@page.sidebar传递给它,这样您的网页视图就不会太大。此外,在后端,您可以使用嵌套表单和部分,因此在外部,具有多个模型的解决方案与您当前的解决方案没有区别,但可以很好地分解为几个问题。

我在嵌套表单上进行了快速谷歌搜索,结果出现了:http://iroller.ru/blog/2013/10/14/nested-model-form-in-rails-4/ 不知道它是否有用,但有疑问你可以自己谷歌或者在轨道上找到一本带有例子的书。

如果您将信息卸载到其他模型,它不仅仍然是OOP,更是如此:

class Page < ActiveRecord::Base
  has_one :sidebar
  accepts_nested_attributes_for :sidebar
end

class Sidebar < ActiveRecord::Base
  belongs_to :page
end

@page.sidebar # => very OOP!

3)STI(单表继承)

这是官方文档页面:http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html

基本上,您可以将每个页面上不需要的信息移动到某些特殊情况中:

class Page < ActiveRecord::Base
end

class ImprintPage < Page
  def do_something_with_terms_and_conditions
  end
end

class IntroPage < Page
  has_one :logo 
end

class Logo < ActiveRecord::Base
  # paperclip stuff
end

您甚至可以从图像中获取徽标,使其成为一种特殊的图像(图像中包含所有回形针的内容)。

ActiveRecord会将类类型存储在数据库中,因此您可以在视图中执行类似的操作(伪代码):

if @page.is_a?(IntroPage)
    # render intro partial

4)Mixins

您可以将问题转移到mixins中:

class Page
  include PageTools::UserMethods
  include PageTools::ImageHandling
end

但要非常小心,因为这可能导致信息遍布/lib文件夹,这可能只会掩盖原始问题。

结论

您可以做更多的事情来使类/模型更少整体(例如服务对象,关注点)。这些只是实现一些重要原则的工具:不要让你的课程变大,并尝试经常分离信息/关注/功能。

大部分内容都是通过练习来实现的,只是永远不要为一个功能添加一堆方法而不首先问自己是否必须真正进入这个确切的模型 - 重建一个巨大的Page怪物模型后,它总是增长太多了痛苦!