Контроллер
При генерации новой модели автоматически создаются файлы клиентского и серверного контроллера
Имеет два основных метода:
-
stop()
останавливает обработку запроса -
redirect( url )
производит переадресацию на другой адрес, вызывает методstop()
, url это строка типа/user/person
илиuser/person
(ведущий слеш не обязателен)
Рассмотрим файл app/client/javascripts/controllers/users.js
клиентского контроллера модели User
на примере:
Nali.Controller.extend Users:
actions:
# объект - список экшенов
# в каждом экшене, включая фильтры before и after
# доступна обрабатываемая коллекция в свойстве @collection,
# фильтры, по которым она отфильтрована в свойстве @filters
# и переданные параметры в свойстве @params
# имя экшена указывается в следующем виде:
# action/filter/filter/:param/:param, где action это само название
# экшена, filter - некий параметр для выборки коллекции
# params - параметр который нужно передать в контроллер
# именование фильтров и параметров различается лишь тем,
# что имена последних начинаются с двоеточия
default: 'index'
# экшен по умолчанию - если не найдено
# совпадения с другими экшенами
# запрос попадет в экшен index, также позволяет сокращать адреса
# т.е. /user или /users, автоматически расцениваются как
# /user/index и /users/index соответственно
before:
# объект - список предварительных фильтров
'person': ->
# метод выполнится перед экшеном person
# @stop() - остановит обработку запроса
# предотвратит запуск экшена и фильтров after
'person, index, account': ->
# метод выполнится перед экшенами person, index и account
'! auth': ->
# метод выполнится перед каждым экшеном кроме auth
'! auth, index': ->
# метод выполнится перед каждым экшеном кроме auth и index
after:
# объект - список последующих фильтров
'person': ->
# метод выполнится после экшена person
# @stop() - остановит обработку запроса
'! index': ->
# метод выполнится после каждого экшена кроме index
index: ->
# тело экшена, срабатывает на запросы начинающиеся с
# /users/index
# /user/index
# /user и /users - при условии, что указана опция default: 'index'
# имя экшена в ссылках можно указывать, как в единственном,
# так и во множественном числе, остальная часть запроса,
# неподходящая под требования экшена, если она есть, будет
# проигнорирована, например при запросе /user/man/18,
# /man/18 - будет проигнорировано т.к. экшен не принимает
# фильтров и параметров
# @collection будет содержать обрабатываемую коллекцию
# согласно заданных фильтров, здесь она будет пуста
# @params объект принятых параметров, здесь он будет пуст
# @filter объект фильтров коллекции, здесь он будет пуст
@collection.add @Application.user
# в коллекцию будет добавлен пользователь
# ранее сохраненный в свойстве user объекта Nali.Application
'person/gender/age': ->
# сработает на запросы
# /users/person
# @collection будет пуста
# @filters = {}
# @params = {}
# -----------------
# /users/person/man
# @collection - список юзеров, у которых: gender is man
# @filters = { gender: 'man' }
# @params = {}
# -----------------
# /users/person/man/18
# @collection - список юзеров, у которых: gender is man, age is 18
# @filters = { gender: 'man', age: '18' }
# @params = {}
# -----------------
# /users/person/man/18/moscow/russia
# @collection - список юзеров, у которых: gender is man, age is 18
# @filters = { gender: 'man', age: '18' }
# @params = {}
# /moscow/russia - проигнорировано
# -----------------
@redirect 'home' unless @collection.length
# перенаправит роутер на адрес /home если коллекция пуста
# запрос попадет в default экшен контроллера Nali.Controller.Homes
# остановит выполнение текущего запроса, вызвав метод @stop()
'account/gender/age/:sortBy/:desc': ->
# сработает на запросы
# /users/account
# @filters = {}
# @params = { sort_by: null, desc: null }
# -----------------
# /users/account/man
# @params = { sort_by: null, desc: null }
# -----------------
# /users/account/man/18
# @filters = { gender: 'man', age: '18' }
# @params = { sort_by: null, desc: null }
# -----------------
# /users/account/man/18/age
# @filters = { gender: 'man', age: '18' }
# @params = { sort_by: 'age', desc: null }
# -----------------
# /users/account/man/18/age/desc
# @filters = { gender: 'man', age: '18' }
# @params = { sort_by: 'age', desc: 'desc' }
@collection.order by: @params.sortBy, desc: !!@params.desc
# список юзеров будет отсортирован по возрасту по убыванию
'auth/:token': ->
# сработает на запросы
# /users/auth
# @filters = {}
# @params = { token: null }
# @collection будет пуста
# -----------------
# /users/auth/324hb3298723f98nf23f09
# @filters = {}
# @params = { token: '324hb3298723f98nf23f09' }
# @collection будет пуста
# -----------------
unless @params.token?
@stop()
# остановит выполнение текущего запроса,
# предотвратит вызов after фильтров
else
@autentication @params.token
# вызов метода контроллера
autentication: ( token ) ->
# какие то действия
При обработке запроса первыми вызываются фильры before
(если они есть), затем тело экшена
и фильры after
(если они есть), фильтры вызываются в том порядке, в каком они описаны. Согласно коду из примера при обращении по адресу /user/account
порядок запуска будет следующим:
-
'person, index, account'
- before фильтр -
'! auth'
- before фильтр -
'! auth, index'
- before фильтр -
'account/gender/age/:sortBy/:desc'
- сам экшен -
'! index'
- after фильтр
При запросе /users/account/man/18/age/desc
роутер выявит совпадение с маршрутом, ведущим в экшен account
контроллера Users
, произведет разбор адреса на фильры { gender: 'man', age: '18' }
и параметры { sort_by: 'age', desc: 'desc' }
, после чего передаст управление контроллеру Users
.
Контроллер создаст запрос в модель User
вида User.where gender: 'man', age: '18
, получит коллекцию отобранных моделей, выполнит before
фильтры, затем экшен account
, в котором отсортирует коллекцию, и, после выполнения фильтров after
, запустит отрисовку видов коллекции командой collection.show 'account'
, где 'account'
- имя выполняемого экшена. В последнюю очередь контроллер даст роутеру команду на смену url в адресной строке браузера.
Если во время выполнения экшена и его фильтров был вызван метод @stop()
, контроллер завершает свою работу на текущем месте в порядке запуска и уничтожает коллекцию, вызвав collection.destroy()
.
Предназначен для работы с моделями и запросами пользователя, каждый контроллер наследуется от общего родителя ApplicationController
и расширяется модулем Nali::Controller
. Данный модуль релизует методы save
, destroy
и select
для работы с моделями, поэтому не стоит создавать свои методы с такими же именами, только если вы намеренно не хотите переопределить их.
Из любого места клиентской части приложения можно обратиться к методам контроллера для получения данных или совершения каких либо манипуляций с помощью метода query('controller.action', params, success, failure)
, который производит запрос к серверу в экшен action
контроллера controller
, передает объект параметров params
. Если на сервере был вызван trigger_success( params )
- запустит success
с параметрами params
, если trigger_failure
, то выполнится failure
. Колбэки success и failure не являются обязательными агрументами. Пример:
class UsersController < ApplicationController
include Nali::Controller
def online
# метод контроллера, params - хэш входящих параметров
user = User.find params[ :id ]
if user.online?
trigger_success 'yes'
# вызовем success-callback на стороне клиента
# передать можно как строку, так и объект
else
trigger_failure 'no'
# вызовем failure-callback на стороне клиента
end
end
end
# запрос из любого места клиентской части приложения
@query 'users.online', id: 1,
( result ) ->
console.log result + ', user online'
( result ) ->
console.log result + ', user offline'
# если пользователь онлайн
# > yes, user online
# если пользователь оффлайн
# > no, user offline
-
params
- хэш полученных с клиента параметров -
client
- текущий клиент -
clients
- список всех подключенных сейчас клиентов
Это методы которые запускаются до или после экшена контроллера, очень похожи на фильтры контроллеров клиентской части, регистрируются спомощью методов:
-
before
регистрирует фильтр выполняющийся перед обращением к любому методу контроллера -
before_only
регистрирует фильтр выполняющийся перед обращением к конкретным указанным методам контроллера -
before_except
регистрирует фильтр выполняющийся перед обращением к любому методу контроллера за исключением указанных -
after
регистрирует фильтр выполняющийся после обращения к любому методу контроллера -
after_only
регистрирует фильтр выполняющийся после обращения к конкретным указанным методам контроллера -
after_except
регистрирует фильтр выполняющийся после обращения к любому методу контроллера за исключением указанных
Для прерывания обработки запроса существует метод stop
, который предотвращает переход обработки запроса в последующие фильтры и экшен (если был вызван в before
фильтре).
Методы-фильтры применимы к уже определенным методам save
, destroy
и select
, а также для удобства их можно выносить в ApplicationController
для применения их в других контроллерах.
class ApplicationController
protected
def check_auth
stop unless @user = client[ :user ]
# остановит запрос перед любым экшеном если в хранилище
# текущего клиента отсутствует модель пользователя
# прикрепленного, например, после авторизации
end
end
class UsersController < ApplicationController
include Nali::Controller
before do check_auth end
# сработает перед обращением в любой метод
before_only :online do
puts 'before_only_online'
# сработает перед обращением в метод online после фильтра check_auth
end
before_except :online, :save do
puts 'before_except_online_save'
# сработает перед обращением в любой метод
# кроме online и save после фильтра check_auth
# метод save уже определен в модуле Nali::Controller
end
after do after_all_methods end
# сработает после обращения в любой метод
after_only :online, :destroy do after_only_online_destroy end
# сработает после обращения в метод online или destroy
# метод destroy уже определен в модуле Nali::Controller
after_except :online do
puts 'after_except_online'
# сработает после обращении в любой метод кроме online
end
def online
end
private
def after_all_methods
puts 'after_all_methods'
end
def after_only_online_destroy
puts 'after_only_online_destroy'
end
end
Если до или после экшена вызывается несколько фильтров, то их вызов происходит в том порядке, в каком они зарегистрированы в коде контроллера.
Предназначены для выборки и отправки моделей по запросу с клиента, регистрируются методом selector
, описаны в разделе моделей (см. Загрузка моделей с сервера)
- Начало работы
- Структура приложения
- Основные компоненты
- Клиентская часть
- Серверная часть