2013-11-21 30 views
0

沒有爲模型下面的代碼:如何在單獨的類中移動驗證方法?

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 

我可以搬進爲了使用它驗證方法的單獨的類在這兩個班?提前致謝。

+0

這是可以做到你想要什麼,但它是非常糟糕的設計。如果您使用Rails 4,請考慮使用問題。 – Max

+0

我使用Rails 3.2。這個版本中沒有關注問題,不是嗎? – malcoauri

+1

不,他們不是,但你可以使用模塊做基本相同的事情。我會在一秒之內發佈答案,但我強烈建議不要這樣做。嚴重的是,不要這樣做。 – Max

回答

0

下面是如何做你想做的。警告其他讀者:這樣做只是要求麻煩。這是非常脆弱的,我想不出爲什麼你會故意在你的代碼中添加如此脆弱的東西,特別是當一個強大的替代品可用時。如果你不關心這個警告,請繼續閱讀。

要在Rails 3中實現這一點,您只需創建一個新模塊來存儲您的通用驗證器,然後使用包含回調函數在任何包含該模塊的類上使用驗證器。

首先,創建一個模塊目錄,如果你還沒有。我更喜歡lib/modules。接下來,通過編輯config/application.rb

# 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中有更好的語法來做這種事情。如果你理解上面的例子,將它轉化爲一個關注點是微不足道的。

+0

因此,如果您強烈建議不要使用此代碼,並且不能使用問題 - 我該怎麼辦? – malcoauri

+0

你應該在兩個地方使用相同的驗證器。即使你有問題,我也不會推薦他們。上述代碼不好的原因是不能保證'Place'和'PlaceClub'永遠都是一樣的。事實上,他們很可能在某個時候發生分歧。所以通過合併驗證者,你只會讓自己陷入困境。 – Max

+0

謝謝,非常好,完成了 – malcoauri

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 /模型/憂慮/ 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