定义动态类方法

时间:2014-03-08 08:51:57

标签: ruby-on-rails ruby

我知道这个问题已被问过好几次了,但我想在这种情况下从来没有。

我尝试为我的模型创建一个“帮助器”(acts_as),用于从status_id自动设置状态。

acts_as_statusable :status, [ :in_progress, closed ]

此帮助程序创建方法statusstatus=(sym)in_progress?closed?和命名范围in_progressclosed

我的帮助工作,这是它放在lib/

中的代码
class ActiveRecord::Base
  def self.acts_as_statusable(*args)
    field_name = args.first
    field_name_id = :"#{field_name}_id"
    statuses = args.second

    # Define getter
    define_method(field_name) do
      return nil if self.send(field_name_id).nil?
      return statuses[self.send(field_name_id)]
    end

    # Define setter
    define_method(:"#{field_name}=") do |v|
      return self.send(:"#{field_name_id}=", statuses.index(v))
    end

    # Define a status? for each status,
    # and a named scope .status
    statuses.each do |status|
      define_method(:"#{status}?") do
        return self.send(field_name) == status
      end
      scope status, -> { where(["#{table_name}.#{field_name_id} = ?", statuses.index(status)]) }
    end

    validates field_name_id, :inclusion => { :in => (0...statuses.length).to_a }
  end
end

现在,问题

我需要为每个使用acts_as_statusable的类创建一个Class方法,名为status_index(sym),从状态返回status_id。

问题是我找到的用于定义类模型的每个解决方案都使用Moduleextendintend,但我无法插入statuses变量acts_as_statusable加入这个模块...

我该怎么做?我使用Rails 4。

2 个答案:

答案 0 :(得分:4)

您可以使用class_evalclass_variable_set

class_variable_set :"@@#{field_name}_options", statuses

class_eval <<-RUBY
  def self.status_index(sym)
    @@#{field_name}_options.index(sym)
  end
RUBY

在你的情况下会给出一个

@@status_options类变量
和a status_index(sym)
返回给定状态的偏移量的方法

答案 1 :(得分:2)

xlembouras - 您的解决方案效果很好!我有两个模型:

class User < ActiveRecord::Base
  acts_as_statusable :status, [ :little, :big ]
end 

class Price < ActiveRecord::Base
  acts_as_statusable :status, [ :in_progress, :closed ]
end

'rails c'执行:

> User.status_index(:little)
=> 0 
User.status_index(:big)
=> 1 
> Price.status_index(:closed)
=> 1 
> Price.status_index(:in_progress)
=> 0 

我修改了结构,并使用了 ForgetTheNorm 编写的代码。 Rails 4,ActiveSupport ::关注使用

lib / active_record_extension.rb:

module ActiveRecordExtension
  extend ActiveSupport::Concern  
end
ActiveRecord::Base.send(:include, ActiveRecordExtension)

config / initializers / extensions.rb:

require "active_record_extension"

<强>配置/初始化/ active_record_monkey_patch.rb

class ActiveRecord::Base     
  def self.acts_as_statusable(*args)
    ...
    # ForgetTheNorm's CODE..
    ...
    # xlembouras CODE:
    class_variable_set :"@@#{field_name}_options", statuses

    class_eval <<-RUBY
      def self.status_index(sym)
        @@#{field_name}_options.index(sym)
      end
    RUBY
  end
end
相关问题