如何在rails模型中保留代码DRY

时间:2012-12-21 08:44:33

标签: ruby-on-rails-3.2 dry

在轨道模型中使用ENUM时,这是一段了不起的代码

  STATUS = {  approval: 0, 
              rejected: 1, 
              idle: 2, 
            }

  def status
    STATUS.key(read_attribute(:status))
  end

  def status=(s)
    write_attribute(:status, STATUS[s])
  end

当我将它粘贴到任何模型中时,效果很好,这正是问题所在。我使用它很多次,所以我想保持代码干。

我尝试将其复制到application_helper.rb,但它不起作用。什么是使其工作而不重复所有其他模型的最佳方法

代码信用:http://www.kensodev.com/tag/enum/

1 个答案:

答案 0 :(得分:1)

该代码可以抽象为模块。

# lib/enumable.rb
module Enumable
  extend ActiveSupport::Concern

  module ClassMethods
    def enum(name, options)
      map = Hash[options.each_with_index.map { |e, i| [e, i] }]

      const_set(name.to_s.pluralize.upcase, map)

      define_method name do
        map.key(read_attribute(name))
      end

      define_method "#{name}=" do |value|
        write_attribute(name, map[value])
      end
    end
  end
end

默认情况下,Rails不会从lib自动加载。将其添加到应用程序配置。

# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)

将新模块包含在模型中。

# app/models/project.rb
class Project < ActiveRecord::Base
  include Enumable
  enum :status, [:approval, :rejected, :idle]
end

$ rails c
Loading development environment (Rails 3.2.9)
1.9.3-p327 :001 > project = Project.new
 => #<Project id: nil, status: nil, created_at: nil, updated_at: nil> 
1.9.3-p327 :002 > project.status = :rejected
 => :rejected 
1.9.3-p327 :003 > project.status
 => :rejected 
1.9.3-p327 :004 > Project::STATUSES
 => {:approval=>0, :rejected=>1, :idle=>2}