модуль ActionDispatch::Routing::Mapper::Scoping
Вы можете организовать группы контроллеров в пространстве имён. Чаще всего вы группируете несколько административных контроллеров в пространстве имён admin. Эти контроллеры размещаются в каталоге app/controllers/admin, и вы можете сгруппировать их вместе в своём роутере:
namespace "admin" do resources :posts, :comments end
Это создаст множество маршрутов для каждого из контроллеров `posts` и `comments`. Для Admin::PostsController, Rails создаст:
GET /admin/posts GET /admin/posts/new POST /admin/posts GET /admin/posts/1 GET /admin/posts/1/edit PATCH/PUT /admin/posts/1 DELETE /admin/posts/1
Если вы хотите направить /posts (без префикса /admin) на Admin::PostsController, вы можете использовать
scope module: "admin" do resources :posts end
или, в отдельном случае
resources :posts, module: "admin"
Если вы хотите направить /admin/posts на PostsController
- (без префикса модуля Admin
-
вы можете использовать
scope "/admin" do resources :posts end
или, в отдельном случае
resources :posts, path: "/admin/posts"
В каждом из этих случаев именованные маршруты остаются такими же, как если бы вы не использовали scope. В последнем случае следующие пути отображаются на PostsController:
GET /admin/posts GET /admin/posts/new POST /admin/posts GET /admin/posts/1 GET /admin/posts/1/edit PATCH/PUT /admin/posts/1 DELETE /admin/posts/1
Публичные методы экземпляров
Ограничение параметра
Позволяет ограничить вложенные маршруты на основе набора правил. Например, чтобы изменить маршруты, разрешив использование точки в параметре id:
constraints(id: /\d+\.\d+/) do resources :posts end
Теперь такие маршруты, как /posts/1 больше не будут действительными, но /posts/1.1 будет. Параметр id должен соответствовать ограничению, переданному в этом примере.
Вы можете использовать это, чтобы также ограничить другие параметры:
resources :posts do
constraints(post_id: /\d+\.\d+/) do
resources :comments
end
end
Ограничение по IP
Маршруты также могут быть ограничены IP-адресом или определённым диапазоном IP-адресов:
constraints(ip: /192\.168\.\d+\.\d+/) do resources :posts end
Любой пользователь, подключившийся из диапазона 192.168.*, сможет увидеть этот ресурс, в то время как любой пользователь, подключившийся за пределами этого диапазона, получит сообщение о том, что такого маршрута нет.
Динамическое сопоставление запросов
Запросы на маршруты могут быть ограничены на основе определённых критериев:
constraints(lambda { |req| req.env["HTTP_USER_AGENT"] =~ /iPhone/ }) do
resources :iphones
end
Вы можете перенести эту логику в класс, если она слишком сложна для маршрутов. В этом классе должен быть определён метод matches? , который возвращает true , если пользователю должен быть предоставлен доступ к этому маршруту, или false , если нет.
class Iphone
def self.matches?(request)
request.env["HTTP_USER_AGENT"] =~ /iPhone/
end
end
Ожидаемое место для этого кода — lib/constraints.
Этот класс используется следующим образом:
constraints(Iphone) do resources :iphones end
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 886
def constraints(constraints = {})
scope(:constraints => constraints) { yield }
end Ограничивает маршруты определённым контроллером
controller "food" do match "bacon", action: "bacon" end
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 774
def controller(controller, options={})
options[:controller] = controller
scope(options) { yield }
end Позволяет установить параметры по умолчанию для маршрута, например:
defaults id: 'home' do match 'scoped_pages/(:id)', to: 'pages#show' end
Используя это, параметр :id по умолчанию будет равен 'home'.
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 895
def defaults(defaults = {})
scope(:defaults => defaults) { yield }
end Ограничивает маршруты определённым пространством имён. Например:
namespace :admin do resources :posts end
Это генерирует следующие маршруты:
admin_posts GET /admin/posts(.:format) admin/posts#index
admin_posts POST /admin/posts(.:format) admin/posts#create
new_admin_post GET /admin/posts/new(.:format) admin/posts#new
edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
admin_post GET /admin/posts/:id(.:format) admin/posts#show
admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy Параметры
Параметры :path, :as, :module, :shallow_path и :shallow_prefix по умолчанию имеют значение имени пространства имён.
Для параметров см. Base#match. Для параметра :shallow_path см. Resources#resources.
# accessible through /sekret/posts rather than /admin/posts namespace :admin, path: "sekret" do resources :posts end # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt> namespace :admin, module: "sekret" do resources :posts end # generates +sekret_posts_path+ rather than +admin_posts_path+ namespace :admin, as: "sekret" do resources :posts end
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 817
def namespace(path, options = {})
path = path.to_s
defaults = {
module: path,
path: options.fetch(:path, path),
as: options.fetch(:as, path),
shallow_path: options.fetch(:path, path),
shallow_prefix: options.fetch(:as, path)
}
scope(defaults.merge!(options)) { yield }
end Ограничивает набор маршрутов заданными параметрами по умолчанию.
Рассмотрим следующее определение маршрута:
scope path: ":account_id", as: "account" do resources :projects end
Это генерирует такие вспомогательные функции, как account_projects_path, также как и resources. Разница здесь в том, что сгенерированные маршруты будут вида /:account_id/projects, а не /accounts/:account_id/projects.
Параметры
Принимает те же параметры, что и Base#match и Resources#resources.
# route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt> scope module: "admin" do resources :posts end # prefix the posts resource's requests with '/admin' scope path: "/admin" do resources :posts end # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+ scope as: "sekret" do resources :posts end
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 726
def scope(*args)
options = args.extract_options!.dup
recover = {}
options[:path] = args.flatten.join('/') if args.any?
options[:constraints] ||= {}
unless nested_scope?
options[:shallow_path] ||= options[:path] if options.key?(:path)
options[:shallow_prefix] ||= options[:as] if options.key?(:as)
end
if options[:constraints].is_a?(Hash)
defaults = options[:constraints].select do
|k, v| URL_OPTIONS.include?(k) && (v.is_a?(String) || v.is_a?(Fixnum))
end
(options[:defaults] ||= {}).reverse_merge!(defaults)
else
block, options[:constraints] = options[:constraints], {}
end
SCOPE_OPTIONS.each do |option|
if option == :blocks
value = block
elsif option == :options
value = options
else
value = options.delete(option)
end
if value
recover[option] = @scope[option]
@scope[option] = send("merge_#{option}_scope", @scope[option], value)
end
end
yield
self
ensure
@scope.merge!(recover)
end
© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.