【问题标题】:How can I dynamically declare these instance methods?如何动态声明这些实例方法?
【发布时间】:2012-05-03 03:59:14
【问题描述】:

我必须在 ActiveRecord 模型上实现这些方法以支持某些所需的视图功能。

我认为必须有一种更紧凑的方式来声明这些方法,可能涉及符号数组和 Array#each 调用。

有什么建议吗?

(顺便说一句,这些是旧列名。)


class Contract < ActiveRecord::Base

  def start_date_displayed
    self.start_date.present? ? self.start_date.strftime("%-m/%-d/%Y") : ''
  end

  def start_date_displayed=(input)
    if input.present?
      self.start_date = Date.strptime input, '%m/%d/%Y'
    end
  end

  def end_date_displayed
    self.end_date.present? ? self.end_date.strftime("%-m/%-d/%Y") : ''
  end

  def end_date_displayed=(input)
    if input.present?
      self.end_date = Date.strptime input, '%m/%d/%Y'
    end
  end

  def ArrivalDate_displayed
    self.ArrivalDate.present? ? self.ArrivalDate.strftime("%-m/%-d/%Y") : ''
  end

  def ArrivalDate_displayed=(input)
    if input.present?
      self.ArrivalDate = Date.strptime input, '%m/%d/%Y'
    end
  end

  def Contract_ReceivedDate_displayed
    self.Contract_ReceivedDate.present? ? self.Contract_ReceivedDate.strftime("%-m/%-d/%Y") : ''
  end

  def Contract_ReceivedDate_displayed=(input)
    if input.present?
      self.Contract_ReceivedDate = Date.strptime input, '%m/%d/%Y'
    end
  end

  def Contract_FinalizedDate_displayed
    self.Contract_FinalizedDate.present? ? self.Contract_FinalizedDate.strftime("%-m/%-d/%Y") : ''
  end

  def Contract_FinalizedDate_displayed=(input)
    if input.present?
      self.Contract_FinalizedDate = Date.strptime input, '%m/%d/%Y'
    end
  end

  def Committee_Date_displayed
    self.Committee_Date.present? ? self.Committee_Date.strftime("%-m/%-d/%Y") : ''
  end

  def Committee_Date_displayed=(input)
    if input.present?
      self.Committee_Date = Date.strptime input, '%m/%d/%Y'
    end
  end

  # ...

end

【问题讨论】:

  • Yossi & xzgyb 谢谢。我希望我能接受这两个答案。我选择了 Yossi,因为它是我实际实施的。

标签: ruby-on-rails ruby metaprogramming


【解决方案1】:
class Contract < ActiveRecord::Base

  %w(start_date end_date).each do |attr_name|
     class_eval <<-METHOD_DEF
         def #{attr_name}_displayed
             self.#{attr_name}.present? ? self.#{attr_name}.strftime("%-m/%-d/%Y") : ''
         end

         def #{attr_name)_displayed=(input)
            if input.present?
              self.#{attr_name} = Date.strptime #{attr_name}, '%m/%d/%Y'
            end
         end


     METHOD_DEF
  end
end

如果只为那些名称以日期结尾的列定义这些方法,那么

class Contract < ActiveRecord::Base

   self.column_names.grep(/date$/i).each do |column_name|

     class_eval <<-METHOD_DEF
         def #{column_name}_displayed
             self.#{column_name}.present? ? self.#{column_name}.strftime("%-m/%-d/%Y") : ''
         end

         def #{column_name)_displayed=(input)
            if input.present?
              self.#{column_name} = Date.strptime #{column_name}, '%m/%d/%Y'
            end
         end             
     METHOD_DEF

  end
end

【讨论】:

    【解决方案2】:

    如果可能,最好避免使用普通的 eval。

    class Contract < ActiveRecord::Base
      class << self
        def attr_displayed *attrs
          attrs.each do |attr|
            displayed = :"#{attr}_displayed"
    
            define_method displayed do
              send(attr).present? ? send(attr).strftime("%-m/%-d/%Y") : ''
            end
    
            define_method :"#{displayed}=" do |input|
              if input.present?
                send :"#{attr}=", Date.strptime(input, '%m/%d/%Y')
              end
            end
          end
        end
      end
    
      attr_displayed :start_date, :end_date, :ArrivalDate, :Committee_Date,
                     :Contract_ReceivedDate, :Contract_FinalizedDate
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多