Маршруты Rails на основе условия
У меня есть три роли: Instuctor, Student, Admin и каждый имеют контроллеры с "домашним" представлением.
так что это прекрасно работает,
get "instructor/home", :to => "instructor#home"
get "student/home", :to => "student#home"
get "admin/home", :to => "admin#home"
Я хочу написать urity тщеславия, как показано ниже, который будет маршрутизироваться на основе роли user_id
на правильной домашней странице.
get "/:user_id/home", :to => "instructor#home" or "student#home" or "admin#home"
Как это сделать?
Ответы
Ответ 1
Вы не можете сделать это с помощью маршрутов, потому что в системе маршрутизации нет информации, необходимой для принятия этого решения. Все Rails на этой точке запроса знают, что параметры имеют и не имеют доступа к чему-либо в базе данных.
Что вам нужно - это метод контроллера, который может загружать любые данные, предположительно, пользовательскую запись, и перенаправлять соответственно с помощью redirect_to
.
Это довольно стандартная вещь.
Update:
Чтобы выполнить все это в рамках одного действия контроллера, вам необходимо разделить свою логику в соответствии с ролью. Пример:
class HomeController < ApplicationController
def home
case
when @user.student?
student_home
when @user.admin?
admin_home
when @user.instructor
instructor_home
else
# Unknown user type? Render error or use a default.
end
end
protected
def instructor_home
# ...
render(:template => 'instructor_home')
end
def student_home
# ...
render(:template => 'student_home')
end
def admin_home
# ...
render(:template => 'admin_home')
end
end
Ответ 2
Я предоставляю альтернативный подход, так как этот вопрос SO поднимается вверху при поиске ролевой маршрутизации в Rails.
Недавно мне нужно было реализовать нечто подобное, но мне хотелось избежать большого количества условных выражений в контроллере - это усугублялось тем фактом, что для каждой из моих пользовательских ролей требуются совершенно разные данные для загрузки и представления. Я решил переместить решающую логику на уровень маршрутизации с помощью Ограничения маршрутизации.
# app/constraints/role_route_constraint.rb
class RoleRouteConstraint
def initialize(&block)
@block = block || lambda { |user| true }
end
def matches?(request)
user = current_user(request)
user.present? && @block.call(user)
end
def current_user(request)
User.find_by_id(request.session[:user_id])
end
end
Самой важной частью приведенного выше кода является метод matches?
, который будет определять, будет ли маршрут соответствовать. Метод передается request
объект, который содержит различную информацию о выполненном запросе. В моем случае я просматриваю :user_id
, хранящийся в cookie сессии, и используя это, чтобы найти пользователя, делающего запрос.
Затем вы можете использовать это ограничение при определении маршрутов.
# config/routes.rb
Rails.application.routes.draw do
get 'home', to: 'administrators#home', constraints: RoleRouteConstraint.new { |user| user.admin? }
get 'home', to: 'instructors#home', constraints: RoleRouteConstraint.new { |user| user.instructor? }
get 'home', to: 'students#home', constraints: RoleRouteConstraint.new { |user| user.student? }
end
С помощью вышеизложенного администратор, отправляющий запрос на /home
, будет перенаправлен на домашнее действие AdministratorsController
, инструктор, делающий запрос на /home
, будет перенаправлен на домашнее действие InstructorsController
, а учащийся, отправляющий запрос на /home
, будет перенаправлен на домашнее действие StudentsController
.
Дополнительная информация
Если вы ищете дополнительную информацию, я недавно написал об этом подходе в моем блоге.