Где разместить общий код в нескольких моделях?
У меня есть две модели, которые содержат один и тот же метод:
def foo
# do something
end
Где я должен это поставить?
Я знаю, что общий код находится в каталоге lib
в приложении Rails.
Но если я поместил его в новый класс в lib
, называемый 'Foo
', и мне нужно добавить его функциональность для обоих моих ActiveRecord models
, я делаю это вот так:
class A < ActiveRecord::Base
includes Foo
class B < ActiveRecord::Base
includes Foo
а затем A
и B
будет содержать метод Foo
так же, как если бы я определил его в каждом?
Ответы
Ответ 1
Создайте модуль, который вы можете поместить в каталог lib
:
module Foo
def foo
# do something
end
end
Теперь вы можете include
использовать модуль в каждом из ваших классов моделей:
class A < ActiveRecord::Base
include Foo
end
class B < ActiveRecord::Base
include Foo
end
Модели A
и B
теперь будут иметь метод foo
.
Если вы следуете соглашениям об именах Rails с именем модуля и именем файла (например, Foo in foo.rb и FooBar в файле foo_bar.rb), Rails автоматически загрузит файл для вас. В противном случае вам нужно будет использовать require_dependency 'file_name'
для загрузки вашего файла lib.
Ответ 2
У вас действительно есть два варианта:
- Используйте модуль для общей логики и включите его в и B
- Используйте общий класс C, который расширяет ActiveRecord и расширяет A и B C.
Используйте # 1, если общая функциональность не является ядром для каждого класса, но применима к каждому классу. Например:
(app/lib/serializable.rb)
module Serializable
def serialize
# do something to serialize this object
end
end
Используйте # 2, если общие функции являются общими для каждого класса, а A и B разделяют естественные отношения:
(app/models/letter.rb)
class Letter < ActiveRecord::Base
def cyrilic_equivilent
# return somethign similar
end
end
class A < Letter
end
class B < Letter
end
Ответ 3
Один из вариантов заключается в том, чтобы поместить их в новый каталог, например app/models/modules/
. Затем вы можете добавить это в config/environment.rb
:
Dir["#{RAILS_ROOT}/app/models/modules/*.rb"].each do |filename|
require filename
end
Это будет require
каждый файл в этом каталоге, поэтому, если вы поместите в каталог ваших файлов следующий файл:
module SharedMethods
def foo
#...
end
end
Затем вы можете просто использовать его в своих моделях, потому что он будет автоматически загружен:
class User < ActiveRecord::Base
include SharedMethods
end
Этот подход более организован, чем размещение этих миксинов в каталоге lib
, потому что они остаются рядом с классами, которые их используют.
Ответ 4
Вот как я это сделал... Сначала создайте mixin:
module Slugged
extend ActiveSupport::Concern
included do
has_many :slugs, :as => :target
has_one :slug, :as => :target, :order => :created_at
end
end
Затем добавьте его в каждую модель, которая ему нужна:
class Sector < ActiveRecord::Base
include Slugged
validates_uniqueness_of :name
etc
end
Это почти красиво!
Чтобы завершить этот пример, хотя это не имеет отношения к вопросу, здесь моя модель slug:
class Slug < ActiveRecord::Base
belongs_to :target, :polymorphic => true
end
Ответ 5
Если вам нужен ActiveRecord:: Base код как часть ваших общих функций, использование абстрактного класса также может оказаться полезным. Что-то вроде:
class Foo < ActiveRecord::Base
self.abstract_class = true
#Here ActiveRecord specific code, for example establish_connection to a different DB.
end
class A < Foo; end
class B < Foo; end
Так просто. Кроме того, если код не связан с ActiveRecord, найдите ActiveSupport::Concerns
как лучший подход.
Ответ 6
Как упоминалось выше, Foo - это способ сделать что-то... Однако, похоже, вам не нужна функциональность, которую вы хотите с базовым модулем. Ниже приведена форма, которую принимает множество плагинов Rails для добавления методов класса и новых обратных вызовов в дополнение к новым методам экземпляров.
module Foo #:nodoc:
def self.included(base) # :nodoc:
base.extend ClassMethods
end
module ClassMethods
include Foo::InstanceMethods
before_create :before_method
end
module InstanceMethods
def foo
...
end
def before_method
...
end
end
end