2013-11-21 4 views
0

Существует следующий код модели:Как перенести методы проверки в отдельный класс?

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

    etc... 
end 

И есть некоторый класс, который имеет те же самые Validations методы:

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

Спасибо, очень хороший и завершенный asnwer – 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 

А (положить это в/приложение/модели/концернах/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 
Смежные вопросы