如何将活动记录类特定属性映射到rails中相应的通用关注方法

Posted

技术标签:

【中文标题】如何将活动记录类特定属性映射到rails中相应的通用关注方法【英文标题】:How to map active record class specific attribute to corresponding general purpose concern methods in rails 【发布时间】:2020-03-21 17:31:56 【问题描述】:

我在我的 rails 应用程序中担心目标是将标签转换为日期范围。基本上我有一个字符串 date_label ,它采用像“明天”这样的值来帮助计算两个日期字段,比如 date_end 和 date_end ,它们是实际日期。概念 date_label、date_start、date_end 是“常见的关注概念”,但它们需要映射到包含关注点的活动记录类中具有特定名称的相应活动记录字段。

这是目前为止的关注代码:

module DateSchedulable
  extend ActiveSupport::Concern
  included do
    before_save :compute_date_range
  end

  LABEL_TO_DATE_RANGE =  
    'asap':  start: Date.today, end: Date.today ,
    'same-day':  start: Date.today, end: Date.today ,
    'next-day':  start: Date.tomorrow, end: Date.tomorrow ,
    'two-day':  start: Date.today, end: Date.today + 2.days ,
    'seven-day':  start: Date.today, end: Date.today + 7.days 
  

  def compute_date_range
    if self.date_label_changed?
      date_range = get_date_label_range(self.date_label)
      self.date_start = date_range[:start]
      self.date_end = date_range[:end]
    end
  end

  def get_date_label_range(date_label)
    if LABEL_TO_DATE_RANGE[date_label.to_sym]
      LABEL_TO_DATE_RANGE[date_label.to_sym]
    elsif Date.is_parseable?(date_label)
      date = Date.parse(date_label)
       start: date, end: date 
    else
       start: nil, end: nil 
    end
  end
end

我特别关心如何在compute_date_range 中处理这个date_label_changed?

例如,我需要将此关注点包含在类HelpList 中,该类具有以下活动记录属性"default_requested_date_label", "default_requested_date_start","default_requested_date_end"。我需要确保我的类特定属性名称和我的一般关注概念之间的映射。理想情况下,我可能想写一些类似的东西:

class HelpList
  include DateSchedulable
  date_label :default_requested_date_label
  date_start :default_requested_date_start
  date_end   :default_requested_date_end
end

但我真的很愿意接受建议,并想知道是否有一种优雅的方式来处理这个问题。

【问题讨论】:

【参考方案1】:

你真的应该重新开始并彻底重新考虑你的方法,因为 Ruby 实际上有 ranges 就是为此目的而构建的:

DATE_RANGES =  
  asap: Date.today..Date.today,
  same_day: Date.today.begininng_of_day..Date.today.begininng_of_day,
  next_day: Date.tomorrow.begininng_of_day..Date.tomorrow.end_of_day,
  two_day: Date.today.advance(days: 2).beginning_of_day..Date.today.advance(days: 2).beginning_of_day,
  seven_day: Date.today..Date.today.advance(days: 7)

当您将范围传递给 .where 时,ActiveRecord 将创建 BETWEEN 查询:

tricenarians = User.where(birth_day: 30.years.ago...40.years.ago)
# SELECT users.* FROM users WHERE users.birth_day BETWEEN ? AND ?

如果您使用的是 Postgres,它实际上有 native timestamp and date range types,因此您可以将范围存储在单个列中。否则,您可以使用Range#beginRange#end 获得界限。

不要陷入使用用户标签作为哈希键的诱惑。使用 I18n 模块或String#dasherize。将两者强耦合是错误的,因为仅更新呈现给用户的标签会破坏代码中的任何引用。

我需要确保我的类特定属性名称之间的映射 和我普遍关心的概念。

您可以通过创建类方法并将列名保存在class instance variables 中或通过动态创建方法来使您的模块可配置。

module DateSchedulable
  # ...
  class_methods do 
    def date_label(attribute_name)
      class_eval do
        @_date_label_attribute = attribute_name
      end
      # or
      class_eval do
        define_singleton_method :date_label_attribute do
          attribute_name
        end
      end
    end
    # ...
  end
end

这种元编程是 Rails 构建回调、验证和关联等内容的方式。请务必阅读 mixin 模式,因为您需要很好地理解 Ruby 风格的 OOP。

【讨论】:

以上是关于如何将活动记录类特定属性映射到rails中相应的通用关注方法的主要内容,如果未能解决你的问题,请参考以下文章

YII2.0AR模式CURD

如何将 Grails 域类映射到 DTO?

如何将状态保存为 db 中的代码,但将它们映射到 rails 中有意义的单词?

从 SQL 到 Rails 活动记录

如何将我的 java 应用程序日志记录事件映射到 GCP Felexible 非兼容 App Engine 中相应的云日志记录事件级别?

使用yii AR 完成单个表的CURD操作