如何通过模块或类在Ruby on Rails中DRY重复的模型方法?

3

你好。我是Ruby on Rails和面向对象编程的新手。

我正在开发一个小型调度程序,并希望DRY我的模型方法。
我阅读了一些关于Rails中使用模块和类的文章,但找不出最佳方法。
类和模块之间的区别
ruby-class-module-mixins

例如:

假设我有两个模型(Datum和Person)。
每个模型都有一个属性,用不同的属性名称存储日期。

我在两个模块中编写了相同的日期验证方法。

我的模型:

class Datum < ActiveRecord::Base
 attr :start_date

 def validate_date
  # same validation stuff with self.start_at
 end
end


class Person < ActiveRecord::Base
 attr :birth_date

 def validate_date
  # same validation stuff with self.birth_date
 end
end


以下是我使用lib/ModelHelper和Datum Model尝试的方法:

class Datum < ActiveRecord::Base
 include ModelHelper

 attr_accessible :start_at

 # Validations
 before_validation :validate_date, :start_at

end


module ModelHelper

 private

 def validate_date *var
  # validation stuff with birth_date and start_at 
 end
end


问题:
在我的情况下,我认为我需要为每个模型属性(:start_at和:bith_date)分配一个参数。但是我找不到方法。

最好的方法是使用模块或类来DRY我的模型?
为什么和如何?


我强烈建议您查看codereview.stackexchange.com。 - Anthony
1
顺便提一下,我最近在CodeReview.SE上发布了一个关于自定义Rails 4验证器的答案:http://codereview.stackexchange.com/questions/71435/reservation-validation/71496#71496 - D-side
@Anthony 我的问题不仅仅是关于代码审查。 它更多地涉及到理解Ruby on Rails中的模块和类,以及给出一个示例。 - stephanfriedrich
@D-side,感谢您的评论,您的回答很有帮助。但是它并没有解答我的问题。 使用模块还是类来DRY我的模型,哪种方式最好? 为什么选择这种方式...? 我期待更多的答案。 - stephanfriedrich
在这种特定情况下,validate_date 可以被拆分成一个验证器类。然后你只需要声明属性和验证规则。足够DRY了。 - D-side
1个回答

0
正如评论中@D-side所说,您最好的选择是创建一个自定义验证器
创建一个app/validators目录,并添加一个名为my_date_validator.rb的文件,内容如下:
# EachValidator is a validator which iterates through the attributes given in the
# options hash invoking the validate_each method passing in the record, attribute
# and value.
#
# All Active Model validations are built on top of this validator.
#
class MyDateValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value_is_valid? # <- validate in here.
      record.errors[attribute] << (options[:message] || "is not a valid date")
    end
  end
end

然后在你的模型中添加:

class Datum < ActiveRecord::Base
  validates :start_date, my_date: true
end

class Person < ActiveRecord::Base
  validates :birth_date, my_date: true
end

my_date 代表 MyDateValidator 类名的第一部分。

如果您将验证器命名为:

  • FooValidator,那么您可以在模型验证中使用 foo。
  • FooBarValidator,那么您可以在模型验证中使用 foo_bar。
  • MyDateValidator,那么您可以在模型验证中使用 my_date。

此外,根据您想要验证的内容,您可能需要查看这个 Gem:

https://github.com/johncarney/validates_timeliness


在这里添加一些参考内容:应用程序特定验证器的首选位置是 app/validators,请参阅 https://github.com/bbatsov/rails-style-guide/blob/master/README.md#app-validators。 - D-side
谢谢您的回复。但是为什么不使用模型呢? - stephanfriedrich
或者在您的示例/ Rails指南中。如果我尝试使用更多自定义验证器(是否应该为每个验证器编写一个验证器类)? - stephanfriedrich
我不明白,my_date: true 代表什么意思? 如果我按照之前提到的方式运行验证(before_validation :validate_date),会发生什么? - stephanfriedrich
谢谢@D-side,我根据你的评论更新了答案。 - DanielBlanco
@stephanfriedrich 我的日期: true 表示为该属性“运行 MyDateValidator”。如果验证器类名称为 FooValidator,则编写 foo: true;如果名称为 FooBarValidator,则编写 foo_bar: true。 - DanielBlanco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接