如何在单独的类中移动验证方法?

时间:2013-11-21 06:40:07

标签: ruby-on-rails

模型有以下代码:

class Place < ActiveRecord::Base
  attr_accessible :address, :name, :latitude, :longitude
  validates :name, :address, :latitude, :longitude, presence: true

  etc...
end

并且有一些类具有相同的验证方法:

class PlaceClub
  include Virtus

  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_reader :club
  attr_reader :place

  attribute :name, String
  attribute :address, String
  attribute :latitude, Float
  attribute :longitude, Float

  validates :name, :address, :latitude, :longitude, presence: true

  etc ...
end

我可以将验证方法移到单独的类中,以便在两个类中使用它吗?提前谢谢。

2 个答案:

答案 0 :(得分:1)

您可以使用ActiveSupport::Concern

更新您的代码,如:

class Place < ActiveRecord::Base
  include CustomPlaceClubValidation
  attr_accessible :address, :name, :latitude, :longitude
  validates :name, :address, :latitude, :longitude, presence: true

  etc...
end

并且(把它放在/ app / models / concerns / custom_place_club_validation中):

module CustomPlaceClubValidation
  extend ActiveSupport::Concern

  include Virtus

  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  included do
    attr_reader :club
    attr_reader :place

    attribute :name, String
    attribute :address, String
    attribute :latitude, Float
    attribute :longitude, Float

    validates :name, :address, :latitude, :longitude, presence: true

    etc ...
  end
end

答案 1 :(得分:0)

以下是如何做你想做的事。警告其他读者:这样做只是在惹麻烦。它非常脆弱,而且我无法想到为什么你会故意在你的代码中添加如此脆弱的东西,特别是当一个强大的替代品随时可用时。如果您不关心此警告,请继续阅读。

要在Rails 3中实现这一点,您只需创建一个新模块来存储您的公共验证器,然后使用include回调在包含该模块的任何类上使用验证器。

首先,创建一个模块目录(如果尚未创建)。我更喜欢lib/modules。接下来,通过编辑config/application.rb

将modules目录添加到加载路径
# config/application.rb
require File.expand_path('../boot', __FILE__)

# Pick the frameworks you want:
# ...

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env)

module AppName
  class Application < Rails::Application
    config.autoload_paths += %W(#{config.root}/lib) # <- Add this line

    # ...
  end
end

接下来,创建模块。对于此示例,我将其命名为文件common_validator.rb。请务必将其放在lib/modules

# lib/modules/common_validator.rb
module CommonValidator
  def CommonValidator.included(mod)
    mod.validates :name, :what, :ever, :params
  end
end

最后,您只需在模型中包含此模块即可。像这样:

class Place < ActiveRecord::Base
  attr_accessible :address, :name, :latitude, :longitude
  include CommonValidator # <- Add this

  etc...
end

你有它。只需确保重新启动Rails服务器即可获取加载路径更改。每当您对模块进行更改时,您还必须重新启动服务器。 (编辑:阅读this question以了解如何在每个请求上重新加载模块)。 Rails 4在ActiveSupport::Concern中有一个更好的语法来执行此类操作。如果你理解上面的例子,将它移植到一个问题是微不足道的。