【问题标题】:Rails4 refactor Model make DRYRails4 重构模型使 DRY
【发布时间】:2016-02-20 03:59:00
【问题描述】:

我尝试优化以下会计模型类,有两个问题:

1) 如何用更优雅的方法替换多个属性设置器?

2)是否有比replace_comma_with_dot方法中的if条件更好的方法

class Accounting < ActiveRecord::Base

  validates :share_ksk, :central_office, :limit_value, :fix_disagio,
            presence: true, numericality: { less_than: 999.99, greater_than_or_equal_to: 0.00 },
            format: { with: /\d*\.\d{0,2}$/, multiline: true, message: I18n.t('accounting.two_digits_after_decimal_point')}

  def share_ksk=(number)
    replace_comma_with_dot(number)
    super
  end

  def central_office=(number)
    replace_comma_with_dot(number)
    super
  end

  def limit_value=(number)
    replace_comma_with_dot(number)
    super
  end

  def fix_disagio=(number)
    replace_comma_with_dot(number)
    super
  end

  def replace_comma_with_dot(number)
    if number.is_a? String
      number.sub!(",", ".")
    elsif number.is_a? Float
      number
    else
      ""
    end
  end

end

正如用户 Pardeep 建议的那样,我正在尝试用 define_method 替换我的吸气剂:

  [:share_ksk=, :central_office=, :limit_value=, :fix_disagio=].each do |method_name|
    self.class.send :define_method, method_name do |number|
      replace_comma_with_dot(number)
      super
    end
  end

我错过了什么?

【问题讨论】:

  • 更新是非常不好的做法
  • 我应该坚持四传手吗?
  • 也许,我已经写了一半的答案——看看有没有更好的方法
  • 您的更新所做的就是所谓的元编程。虽然这在某些情况下是可以的 - 它必须受到限制,否则可能会在更大的应用程序中导致冲突和问题

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


【解决方案1】:

我将提取功能并将其附加到 StringInteger 类中,而不是在您的模型中添加方法:

#lib/ext/string.rb
class String
  def replace_comma_with_dot
    number.sub!(",",".") #Ruby automatically returns so no need to use return
  end
end

这 - 如果您的 numberstring 将允许您执行以下操作:

number = "67,90"
number.replace_comma_with_dot

要在应用程序中使用它,setter 没问题。您可以按如下方式实现您的功能:

 def fix_disagio=(number)
    self[:fix_disagio] = number.replace_comma_with_dot
 end

您的更新没问题,但我自己会回避它,因为它会造成不必要的膨胀。

当您从数据库中提取时,我一直在寻找一种设置属性的方法,但后来我意识到,如果您每次调用模型时都必须设置它,那么肯定会出现问题。

我个人会考虑在db 级别更改此设置,否则,您可能可以使用某种localization 来确定您是否需要dotcomma

这里有一个很好的答案,提倡adding to the ActiveRecord::Base class

class ActiveRecord::Base
  def self.attr_localized(*fields)
    fields.each do |field|
      define_method("#{field}=") do |value|
        self[field] = value.is_a?(String) ? value.to_delocalized_decimal : value
      end
    end
  end
end

class Accounting < ActiveRecord::Base
  attr_localized :share_ksk
end

【讨论】:

  • 感谢@richpeck,我重视您的见解和反馈!
【解决方案2】:

您可以使用define_method动态定义方法,您可以细化更多信息here

你可以用这个更新你的replace_comma_with_dot

def replace_comma_with_dot(number)
  return number.sub!(",", ".") if number.is_a? String
  return number if number.is_a? Float
  ""
end

结束

【讨论】:

  • 感谢帕迪普!我在用 define_method 替换 setter 时遇到了一些麻烦。你能详细说明一下吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多