module 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
Открытые методы экземпляра
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1176
def constraints(constraints = {}, &block)
scope(constraints: constraints, &block)
end Ограничение параметров
Позволяет ограничивать вложенные маршруты на основе набора правил. Например, чтобы изменить маршруты и разрешить символ точки в параметре 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(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
resources :iphones
end
Вы можете вынести эту логику в отдельный класс, если она слишком сложна для файла маршрутов. В этом классе должен быть определён метод matches?, который возвращает либо true, если пользователю должен быть предоставлен доступ к этому маршруту, либо false, если доступ предоставляться не должен.
class Iphone
def self.matches?(request)
/iPhone/.match?(request.env["HTTP_USER_AGENT"])
end
end
Подходящим местом для этого кода было бы lib/constraints.
Затем этот класс используется следующим образом:
constraints(Iphone) do resources :iphones end
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1052 def controller(controller) @scope = @scope.new(controller: controller) yield ensure @scope = @scope.parent end
Ограничивает область действия маршрутов указанным контроллером
controller "food" do match "bacon", action: :bacon, via: :get end
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1187
def defaults(defaults = {})
@scope = @scope.new(defaults: merge_defaults_scope(@scope[:defaults], defaults))
yield
ensure
@scope = @scope.parent
end Позволяет задать параметры по умолчанию для маршрута, например так:
defaults id: 'home' do match 'scoped_pages/(:id)', to: 'pages#show' end
При таком использовании параметр :id здесь по умолчанию будет равен ‘home’.
# File actionpack/lib/action_dispatch/routing/mapper.rb, line 1097
def namespace(name, deprecated_options = nil, as: DEFAULT, path: DEFAULT, shallow_path: DEFAULT, shallow_prefix: DEFAULT, **options, &block)
if deprecated_options.is_a?(Hash)
as = assign_deprecated_option(deprecated_options, :as, :namespace) if deprecated_options.key?(:as)
path ||= assign_deprecated_option(deprecated_options, :path, :namespace) if deprecated_options.key?(:path)
shallow_path ||= assign_deprecated_option(deprecated_options, :shallow_path, :namespace) if deprecated_options.key?(:shallow_path)
shallow_prefix ||= assign_deprecated_option(deprecated_options, :shallow_prefix, :namespace) if deprecated_options.key?(:shallow_prefix)
assign_deprecated_options(deprecated_options, options, :namespace)
end
name = name.to_s
options[:module] ||= name
as = name if as == DEFAULT
path = name if path == DEFAULT
shallow_path = path if shallow_path == DEFAULT
shallow_prefix = as if shallow_prefix == DEFAULT
path_scope(path) do
scope(**options, as:, shallow_path:, shallow_prefix:, &block)
end
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 Sekret::PostsController rather than Admin::PostsController 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 989
def scope(*args, only: nil, except: nil, **options)
if args.grep(Hash).any? && (deprecated_options = args.extract_options!)
only ||= assign_deprecated_option(deprecated_options, :only, :scope)
only ||= assign_deprecated_option(deprecated_options, :except, :scope)
assign_deprecated_options(deprecated_options, options, :scope)
end
scope = {}
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?(Integer))
end
options[:defaults] = defaults.merge(options[:defaults] || {})
else
block, options[:constraints] = options[:constraints], {}
end
if only || except
scope[:action_options] = { only:, except: }
end
if options.key? :anchor
raise ArgumentError, "anchor is ignored unless passed to `match`"
end
@scope.options.each do |option|
if option == :blocks
value = block
elsif option == :options
value = options
else
value = options.delete(option) { POISON }
end
unless POISON == value
scope[option] = send("merge_#{option}_scope", @scope[option], value)
end
end
@scope = @scope.new scope
yield
self
ensure
@scope = @scope.parent
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 Admin::PostsController 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
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.