Rails 我切割大 model 的方法

linjunhalida · March 04, 2013 · Last by yedingding replied at March 05, 2013 · 3958 hits

有的时候,rails 里面一个 model 的工作太多,在一个文件里面都放不下了,于是我需要拆分出不同的模块。我的拆分方法是这样的:

user.rb 里面:

class User < ActiveRecord::Base

  def self.has_module name
    eval "
    define_method :#{name} do
      @#{name} ||= User#{name.to_s.camelize}.new(self)
    end
    "
  end

  has_module :account
  has_module :displayer
  has_module :privacy
  has_module :message

end

然后对应的职责模块:

class UserDisplayer

  def initialize user
    @user = user
  end

  def address
    "#{@user.city}#{', ' unless @user.city.blank? or @user.country.blank?}#{@user.country}"
  end

end

然后调用的方式:

user = User.find 5
user.displayer.address

当用到对应模块的时候,才会加载该模块。

原先我考虑过采用 concerns,但是看起来只是把代码移动到另外的地方去, 当需要调试的时候很不方便,不知道代码放到哪里了。所以不觉得好用。

大家有什么看法?

这个方法有局限性吧,关键是 validation scope 这样的语句 不能移走吧。。

没有必要这样 使用 concern 即可

@iBachue validation scope 是不能移走,但是为什么要移走?它们和 model 是一体的。 @chucai 我原先也用 concern 的方式,但是 debug 的时候,往往找不到一个方法到底放到哪里去了。 @zlx_star 恩,我就是用这篇里面的方法重构的。

抽普通 module 就行。另外你那个 UserDisplayer 更象是 View 级别的逻辑,可能用 presenter 比较恰当。而 account 很可能单独建个 Account model 就行了。

@zlx_star 这个资料很棒。

#2 楼 @chucai #5 楼 @linjunhalida 我看到 rails 4 里面默认有了两个 concern 的文件夹。请教 concern 的使用方法,有没有相关资料可以查看?

#9 楼 @zlx_star 发到 kindle 里面晚上看,也算是个长文了。

#5 楼 @linjunhalida 提供一些代理方法可能会更好,比如 user.address 用起来比 user.displayer.address 更自然一点。像 rails 的 active_record query 一样。

@ashchan presenter 挺不错,可以用用 https://github.com/drapergem/draper @zlx_star 问题是出现错误的时候找不到,我现在会在上面的基础上加上: delegate :address, :rank, :startup_product, :all_ideas, to: :displayer

我的理解是:能不用eval就不用eval,危险~ 用instance_eval代替吧

@linjunhalida 哈,今天刚写了一篇博客来阐述一下我一般用的方法。http://yedingding.com/2013/03/04/steps-to-refactor-controller-and-models-in-rails-projects.html 像你上面那么用的话,直接用 delegate 更好。

You need to Sign in before reply, if you don't have an account, please Sign up first.