2012-02-13 6 views
1

Я понимаю, что application_controller.rb - это место, где можно разместить все методы и т. Д., Которые вы хотели бы сделать доступными во всех своих контроллерах, поскольку все они наследуются от этого класса. Отлично.Rails эквивалент ApplicationController для моделей

Но что эквивалентно для моделей? Другими словами, я хочу место, где я могу создать пару суперклассов, на которые мои модели наследуют.

Например, у меня есть метод, который ищет разные таблицы для записей во всех CAPS через REGEXP в Mysql. Я хотел бы иметь возможность создать метод только один раз и вызвать его для разных таблиц/моделей.

Что такое Rails?

Я думал, что могу создать класс, который наследует от ActiveRecord :: Base (как и все модели), поместить туда методы и затем наследовать все мои модели из этого класса. Но мысль, что, несомненно, будет лучший способ сделать это.

Спасибо.

Редактировать

За ответ Семена я редактирую пост, чтобы показать маршруты я использую. Он работает сейчас:

# models/dvd.rb 
require 'ModelFunctions' 
class Dvd < ActiveRecord::Base 
    extend ModelFunctions 
    ... 
end 

# lib/ModelFunctions.rb 
module ModelFunctions 
    def detect_uppercase(object) 
     case object 
     ... 
     where("(#{field} COLLATE utf8_bin) REGEXP '^[\w[:upper:]]{5,}' ").not_locked.reorder("LENGTH(#{field}), #{table}.#{field} ASC") 
    end 
end 

В конфигурации/application.rb

config.autoload_paths += %W(#{config.root}/lib) 
+0

Не используйте 'require 'model_common'' - используйте' include ModelCommon'; см. http://stackoverflow.com/questions/318144/what-is-the-difference-between-include-and-require-in-ruby – Thilo

+0

Спасибо Thilo, ссылка в вашем ответе говорит, что нужно использовать, поэтому я попробовал что. Но попытка включить ModelCommon дает мне эту ошибку: «Ожидаемые .../app/models/model_common.rb для определения ModelCommon». Я думал, что вы «обязал» файл, а затем «включил» методы. Это неправильно? – kakubei

ответ

1

Поместите метод многократного использования в некоторый модуль рядом с вашим классом Dvd. Вы можете переместить его в отдельный файл позже.

# app/models/dvd.rb 
module CaseInsensitiveSearch 
    def case_insensitive_search(field, value) 
    # searching field for value goes here 
    end 
end 

class Dvd 
end 

После расширения класса с помощью модуля вы можете использовать case_insensitive_search для класса. Включение модуля сделает case_insensitive_search методом экземпляра, который не является тем, что вы хотите.

class Dvd 
    extend CaseInsensitiveSearch 
end 

Dvd.case_insensitive_search("title", "foo") 

И, конечно, вы можете использовать его внутри класса Dvd.

class Dvd 
    def self.search(query) 
    case_insensitive_search("title", query) 
    end 
end 

Dvd.search("foo") 

Теперь, когда вы убедились, что это работает, вы, вероятно, захотите переместить его в отдельный файл и использовать его в нескольких классах. Поместите его в lib/case_insensitive_search.rb и убедитесь, что у вас есть эта строка в config/application.гь:

config.autoload_paths += %W(#{config.root}/lib) 

Теперь вы можете требовать его в любом месте вы хотите использовать:

require 'case_insensitive_search' 

class Dvd 
    extend CaseInsensitiveSearch 
end 

Последнее, что я хотел бы предложить. Создайте несколько модулей со значимыми именами. Поэтому вместо CommonModel есть CaseInsensitiveSearch и т. Д.

+0

Итак, это связано с первой мыслью, которую я создал: создать файл с этими методами, а затем все мои модели наследуют этот файл/класс. Это верно? – kakubei

+0

Нет, вы можете поместить любой код в файл, а не только классы. Чтобы методы были доступны вне файла, вы определяете модуль и размещаете в нем методы. –

+0

Таким образом, вы не можете просто вводить туда методы, вам нужно обернуть их в один и тот же 'module CaseInsensitiveSearch; конец' предмет. И вы делаете то же самое «расширяете CaseInsensitiveSearch» в классе Dvd. Нет новых классов и никакого наследования. –

2

Посмотрите на Mixins, например, здесь:

http://ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html

В приложении Rails можно создать модуль в каталоге lib, который определяет ваши методы, а затем include в ваших моделях.

EDIT: Для конкретного примера вы пытаетесь определить метод класса. Вы можете сделать это в Mixin, как это:

module Common 
    module ClassMethods 
    def detect_uppercase(object) 
     case object 
     when 'dvd' 
      field = 'title' 
     ... 
     end  
     where("(#{field} COLLATE utf8_bin) REGEXP '^[\w[:upper:]] {5,}').not_locked.reorder('LENGTH(title), title ASC')" 
    end 
    end 

    def self.included(base) 
    base.extend(ClassMethods) 
    end 
end 

Теперь, когда вы include Common в модели, класс этой модели будет расширена, чтобы включить новые методы класса, и вы должны быть в состоянии назвать Dvd.detect_uppercase.

+0

Да, микширование вписывается в идеологию ActiveRecord, чтобы поделиться какой-то функциональностью. Наследование от суперкласса имеет смысл для использования Singe Table Inheritance pattern – Anatoly

+0

отлично, это звучит многообещающе. Итак, используя mixins, я мог бы создать метод, который изменил бы определенные параметры на основе модели, которая называла его? Я попробую. Благодарю. – kakubei

+0

Это выглядело многообещающим, но при вызове 'Dvd.detect_uppercase ('dvd')' после внесения изменений в ваше изменение, последняя ошибка такова: 'NameError: неинициализированная константа Common :: ClassMethods' – kakubei