【问题标题】:Where to put custom callbacks that I use in several models在哪里放置我在多个模型中使用的自定义回调
【发布时间】:2014-05-09 08:16:04
【问题描述】:

假设我有两个具有相同回调的模型:

class Entry < ActiveRecord::Base
    belongs_to :patient
    validates :text, presence: true
    after_validation :normalizeDate

    def normalizeDate
      self.created_at = return_DateTime(self.created_at)
    end
end

class Post < ActiveRecord::Base
    after_validation :normalizeDate

    def normalizeDate
      self.created_at = return_DateTime(self.created_at)
    end
end

我在哪里可以放置共享回调代码?谢谢

 def normalizeDate
   self.created_at = return_DateTime(self.created_at)
 end

【问题讨论】:

  • 不是验证码。这是回调。
  • 对不起!我会改变我的问题
  • 我认为这是一个很好的问题,但只是一个旁注:如果你只有 2 个模型,复制是可以的。
  • @sytycs Dry is Dry 我的朋友 :) 2 次相同的代码已经重复,想象一下几个月后您自己必须维护您的代码,而忘记更新其中的一个?跨度>
  • @BenjaminSinclaire 我不同意。如果在 2 个月内我决定更改日期标准化的方式,我可能会考虑代码中发生这种情况的 2 个位置。我只是不喜欢在重构上操之过急。见:stackoverflow.com/questions/2298272/…

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


【解决方案1】:

Marek 的回答很好,但 Rails 的方式是:

module NormalizeDateModule
  extend ActiveSupport::Concern

  included do
    after_validation :normalize_date
  end

  def normalize_date
    self.created_at = return_DateTime(created_at)
  end
end

Doc here.

(你有一个专门的文件夹:models/concerns)

【讨论】:

  • 对。我忘了Concern
  • 我如何在我的模型中调用它?
  • @JohnSmith 和我的解决方案一样。
  • 为了测试您的解决方案,我将self.created_at = self.created_at + 2.days 放入def normalize_date。但我总是得到错误:undefined method +' for nil:NilClass` 因为self.created 似乎没有被定义!我错了什么?谢谢
  • @JohnSmith created_atnil,直到创建对象。替换为:self.created_at = (created_at || Time.now) + 2.days
【解决方案2】:

您可以定义自己的模块:

module NormalizeDateModule
  def self.included(base)
    base.class_eval do
      after_validation :normalize_date
    end
  end

  def normalize_date
    self.created_at = return_DateTime(created_at)
  end
end

并将其包含在您想要此行为的每个类中:

class Entry < ActiveRecord::Base
  include NormalizeDateModule
  # ...
end

我不确定我的代码是否没有错误(我没有测试过),以它为例。

【讨论】:

  • 如果您将其设为模块而不是 class NormalizeDateModule 并包含,则上述代码将起作用。参考:stackoverflow.com/questions/1698225/… 也使用了上面的代码。用户已将其标记为有效答案。
  • @SreekanthGS 当然。我的意思是module,但我写了class。 :) 谢谢。
  • 抱歉这个问题,但我必须在哪里保存模块?我的意思是在models-文件夹中为normalize_date_module.rb?
  • @JohnSmith 是的,我认为models 文件夹最适合这个。是的,它应该像你写的那样命名。
  • @JohnSmith 不,因为它可以在许多模型上重复使用,所以它应该放在单独的文件中。
【解决方案3】:

Rails 4 的方式是使用ActiveSupport::Concern

文件models/concerns/date_normalizer.rb

module Concerns
  module DateNormalizer
    extend ActiveSupport::Concern

    included do |base|
      base.after_validation :normalize_date
    end

    def normalize_date
      self.created_at = return_DateTime(self.created_at)
    end
  end
end

文件model/entry.rb

class Entry < ActiveRecord::Base
  include Concerns::DateNormalizer

  belongs_to :patient
  validates :text, presence: true
end

文件models/post.rb

class Post < ActiveRecord::Base
  include Concerns::DateNormalizer
end

注意:我为你将normalizeDate改名为normalize_date

【讨论】:

  • 迄今为止最好的答案!我去看看!
  • 对不起,我的习惯是有几个关注目录,最好使用默认的 rails 开始
  • 这是另一个问题:我假设您正在测试新记录,对于新记录,在验证时(因为您的回调是 after_validation)字段 created_at 尚未设置铁路
  • 你有这个错误意味着你的回调正常工作(因为错误来自你的回调代码)
  • 请验证此答案并发布另一个问题,否则会变得混乱
猜你喜欢
  • 2015-07-25
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多