2010-02-28 5 views
13

У меня есть несколько методов, которые я хотел бы разделить между моделями, а не копировать и вставлять их. В контроллере я могу это сделать, поместив методы в application_controller.rb, который автоматически включается в каждый контроллер. Есть ли подобные модели для моделей?Как обмениваться кодами между моделями? (Rails 2.3)

Спасибо!

ответ

16

Вы можете создать файл с именем functionality.rb или что-то подобное в lib директории вашего приложения Rails. Сделайте файл с именем после того, как модуль выполнит автозагрузку при запуске Rails. Например, если я хотел бы добавить пометки на несколько моделей, я бы создать файл с именем lib/flagging.rb, и это будет выглядеть следующим образом:

module Flagging 
    # Flags an object for further review 
    def flag! 
    self.update_attribute(:flagged, true) 
    end 

    # Clears all flags on an object 
    def deflag! 
    self.update_attribute(:flagged, false) 
    end 
end 

В каждой модели, которую я хотел, чтобы добавить эту функциональность, я бы выполните следующие действия:

class Foo < ActiveRecord::Base 
    include Flagging 
end 

Я бы тогда быть в состоянии сделать что-то вроде:

foo = Foo.create 
foo.flag! 
+0

спасибо! вот что я в итоге использовал –

+1

чувак. Это все о каталоге lib. Я начал вводить там больше кода, и это просто удобное место для организации вещей. –

3

Вы можете либо a) сделать что-то похожее на application_controller и создать класс модели, из которого другие могут подклассы, либо b) использовать модуль.

2

Существует несколько способов совместного использования методов между двумя классами моделей.

  • Использовать inheritance, если модели связаны друг с другом, например. общий родительский класс, содержащий методы, или один подкласс, другой, который содержит методы.
  • Использование modules/mixins, которые могут быть разделены между несколькими моделями
+0

'Превратите эти методы в вспомогательные методы, к которым имеют доступ обе модели. - Я думал, что модели не имеют доступа к вспомогательным методам. Как это возможно (кажется, что самый чистый метод для того, что я пытаюсь сделать) –

+0

Вы правы. Я думал о полезных методах, а не о «вспомогательных методах» в смысле рельсов. Таким образом, подход mixin был бы более полезен, чем утилиты. – marklai

4

Верхнее решение выше работало для меня. В Rails 3 я также обнаружил, что мне также пришлось обновить файл application.rb с помощью: config.autoload_paths += Dir["#{config.root}/lib/**/"] как здесь: Best way to load module/class from lib folder in Rails 3?

0

Чтобы добавить ответ Джошу, иногда вам может понадобиться поделиться некоторым кодом, определяющим полиморфную ассоциацию. Вы не можете просто поставить вызов has_many метода в модуле, потому что вы получите сообщение об ошибке, например, в модуле, который называется Votable:

undefined method `has_many' for Voteable:Module (NoMethodError) 

Так вместо этого, вам нужно использовать метод self.included(base) и base.instance_eval. Вот пример с моим Voteable модулем:

module Voteable 

    def self.included(base) 
    base.instance_eval do 
     has_many :votes, as: :voteable 
     has_many :voters, through: :votes 
    end 
    end 

    def voted_up_by?(user) 
    user and votes.exists?(value: 1, voter_id: user) 
    end 

    def voted_down_by?(user) 
    user and votes.exists?(value: -1, voter_id: user) 
    end 

end 

Теперь вы можете include Voteable в моделях, которые будут иметь такое поведение. Это выполнит метод self.included(base), и он определит ассоциацию для включенного класса.

+0

В Rails 3 это еще проще - вы можете заменить базу 'def self.included (base).instance_eval' с 'расширением ActiveSupport :: включен Концерн'. –

Смежные вопросы