Учебный Центр "Мастер ИТ" УлГТУ
#ER-diagrams https://github.com/PanfilovDenis/masterit/blob/feature/er-diagrams/erd.pdf
#app/repositories Модуль инкапсулирующий локигу запросов к базе. Иными словами туда помещаем различные скоупы. Пример:
module CompetitionRepository
extend ActiveSupport::Concern
include BaseRepository
included do
scope :started, where(state: :started)
scope :current, where(year: Time.current.year)
end
end
Использование, теперь вместо Completition.where(state: :started)
можно использовать более понятную форму Completition.started
Также туда помещаются любые классы с обращением в базу данных.
#app/inputs
Тут содержатся кастомные инпуты для simple form. Иным образом там пишутся свои классы для отображения полей в симпл форм
Пример:
=f.input :name as: :preview
Используется во вьюхах.
#app/types Бывает мы сталкиваемся с тем, что нам нужно изменить поведение класса модели, и мы наследуемся от класса и добавляем не стандартное поведение, чтобы нам было легче ориентироваться в будущем и не путаться. Соответственно мы в контроллере будем видеть что название другое и не будем забывать что он себя ведет не стандартно. Пример:
# стандартное поведение
Work.new
# не стандартное поведение
WorkCreateType.new
#app/mailers Подробное описание работы с отправкой почты : http://guides.rubyonrails.org/action_mailer_basics.html Тут хранится все что связано с логикой отправки сообщений на почту.
#app/reports Тут хранится класс отвечающий за генерацию сертификата.
#Иерархия контроллеров В большинстве встречавшихся мне rails проектов, структура контроллеров не имеет никакой организации и проект растет как придется. В больших проектах это приводит к тому что контроллеры становятся огромными (с десятками actions), а условные фильтры растягиваются на весь экран. Разобраться в таком коде бывает очень не просто.
Поработав с большим количеством rails проектов, у меня был сформирован подход к организации иерархии контроллеров, которая позволила унифицировать их структуру и упростить код.
#Верхний уровень
В первую очередь удобно на верхнем уровне расположить основные неймспейсы проекта, такие как web, mobile, api, feeds и другие. При этом модуль admin будет находиться в web.
Внутри апи можно так же выделить подмодули, разделенные по версии, например, v1, v2. Либо делать папки на верхнем уровне api1, api2 и т.п. тыц
Я использую такую структуру даже в самых простейших случаях. Практика показывает, что любая из этих составляющих легко может добавиться тогда, когда этого никто не планировал.
Для каждого модуля создается Namespace::ApplicationController для того чтобы не смешивать логику подходящую для конкретных неймспейсов.
Но в роутинге будут небольшие отличия для разных модулей. Web задается как scope. В результате мы получим хелперы без лишних префиксов, а вот для остальных используется namespace.
#Вложенные ресурсы
Начну сразу с примера: профайл пользователя на сайте. Он может быть доступен по такому урлу /users/:id и его контроллер UsersController. Список постов пользователя доступен по /users/:id/posts. Соответственно мы имеем PostsController с index внутри которого получаем посты по юзеру. Затем у нас появляется задача выводить все посты одним списком. Мы используем тот же контроллер posts и добавляем туда метод index_all. При этом юзер тут уже не нужен. В конце концов, добавляя множество представлений, появится часть методов которые выводят эти посты (и обрабатывают их) для юзера, а часть без него. Дальше появятся фильтры, например, before_filter :load_user, :only => [:index …], и так до тех пор, пока не останется людей способных понимать что тут происходит.
Тоже самое повторится для вывода комментариев, лайков и многого другого. При этом вывод постов может быть не только по пользователю, но и по категории и по многим другим связям в которых посты будут вложенными ресурсами.
В данном случае так же будет разумным создать модули для соответствующих ресурсов.
И для каждого неймспейса будет собственный ApplicationController содержащий общие методы модуля.
Для всех контроллеров находящихся в этом модуле будет доступен current_section без фильтров.
#Профит:
Контроллеры становятся меньше и проще. Глядя на структуру контроллеров уже много можно сказать о том как организован проект и чего можно ожидать в конкретном контроллере. Уходит много условных фильтров. Упрощается тестирование; Единый организационный подход;
Так же, для удобства и единообразия, входные контроллеры неймспейса обзываются welcome. И подключаются в роутах через root :to => ‘welcome#index’ внутри соответствующего scope. Реальный пример:
Рассмотрим как организовать контроллеры на реальном примере. Допустим потребовалось сделать интеграцию с facebook.
При подходе в лоб, был бы сделан какой нибудь контроллер FacebookController, в который помещались бы все методы для работы с фейсбуком. В итоге мы бы получили часть методов, которая должна работать только из аккаунта пользователя, а часть только для тех кто не авторизован и т.п.
#Подход с разделением:
resource :facebook, :only => [:new, :create]
В данном случае о пользователе еще ничего не известно, а вот при изменении интеграции (например настройка автошаринга) или удалении мы работаем с конкретным пользователем. Это можно реализовать, например, так:
# app/controllers/web/account/facebook_controller.rb
resource :account do
scope :module => :account do
resource :facebook, :only => [:edit, :update, :destroy]
end
end
А если понадобится дать возможность интегрироваться уже авторизованному юзеру? Тогда в последний пример добавляем :new, :create.
В итоге вместо одного контроллера мы получили два (но может быть и больше если задача того потребует), но при этом все методы сгруппированы по вариантам использования.
git clone https://github.com/PanfilovDenis/masterit.git
cd masterit
bundle install
bundle exec rake db:create db:migrate db:seed
bundle exec unicorn
Теперь в браузере можно будет открыть сайт, по умолчанию он находится по ссылке http://localhost:8080/