В основе статьи лежит ситуация, с которой я и мои коллеги столкнулись
при работе над одним проектом.
Представим себе следующее. У меня есть модель Item:
Листинг 0 - Модель Item app/models/item.rb
12
classItem<ActiveRecord::Baseend
Затем нам дали задачу на новую фичу: пользователи могут создавать списки
и добавлять туда элементы. Мы сразу видим модель List:
Листинг 1 - Модель List app/models/list.rb
12
classList<ActiveRecord::Baseend
Но для хранения связи между элементом и листом мы решили использовать модель
не ListItem, а положить ее в namespace List, т.е. логически
выделить эту часть подсистемы, т.к. мы предполагаем, что будут еще связанные модели.
И получается следующее:
Листинг 2 - Модель List::Item app/models/list/item.rb
1234
moduleListclassItem<ActiveRecord::Baseendend
Как бы все идет хорошо до тех пор, пока вы не захотите использовать
List::Item модель где-нибудь в коде приложения:
Листинг 3 - Использование List::Item в rails console
1234567891011121314151617
Loading development environment (Rails 4.0.4)2.1.2 :001 > List::Item.new
TypeError: List is not a module
from /Users/sergio/Work/railsapps/namespace_collision_demo/app/models/list/item.rb:1:in `<top (required)>' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:424:in `load' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:424:in `block in load_file' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:616:in `new_constants_in' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:423:in `load_file' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:324:in `require_or_load' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:463:in `load_missing_constant' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/activesupport-4.0.4/lib/active_support/dependencies.rb:184:in `const_missing' from (irb):1
from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/railties-4.0.4/lib/rails/commands/console.rb:90:in `start' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/railties-4.0.4/lib/rails/commands/console.rb:9:in `start' from /Users/sergio/.rvm/gems/ruby-2.1.2/gems/railties-4.0.4/lib/rails/commands.rb:62:in `<top (required)>' from bin/rails:4:in `require' from bin/rails:4:in `<main>'
Есть несколько путей решения этой проблемы.
Решение 0 - Внести название модуля в название класса
Я до конца не понимаю почему, но вот если изменить код модели
List::Item на следующий:
Листинг 4 - Решение 0 для модели List::Item app/models/list/item.rb
Решение 2 - К черту всю эту возню с объектной моделью!
В данном случае предлагается поступить следующим образом: выделить
namespace и ложить туда все модели, которые логически связаны. В
соответствии с нашим примером будет следующее:
Листинг 9 - Модель Lists::List app/models/lists/list.rb
1234
moduleListsclassList<ActiveRecord::Baseendend
Листинг 10 - Модель Lists::Item app/models/lists/item.rb
1234
moduleListsclassItem<ActiveRecord::Baseendend
Однозначным плюсом данного подхода является то, что все модели лежат в
одной папке и если вам нужно выпилить данный кусок функционала, то вот
оно все в папке лежит - не нужно шарится среди несколько десятков
моделей в папке app/models.