mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Implementing Routing Concerns
This pattern was introduced as a plugin by @dhh. The original implementation can be found in https://github.com/rails/routing_concerns
This commit is contained in:
parent
fa736e69a1
commit
0dd24728a0
2 changed files with 117 additions and 1 deletions
|
@ -909,7 +909,7 @@ module ActionDispatch
|
|||
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
|
||||
# a path appended since they fit properly in their scope level.
|
||||
VALID_ON_OPTIONS = [:new, :collection, :member]
|
||||
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param]
|
||||
RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
|
||||
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
||||
|
||||
class Resource #:nodoc:
|
||||
|
@ -1046,6 +1046,8 @@ module ActionDispatch
|
|||
resource_scope(:resource, SingletonResource.new(resources.pop, options)) do
|
||||
yield if block_given?
|
||||
|
||||
concerns(options[:concerns]) if options[:concerns]
|
||||
|
||||
collection do
|
||||
post :create
|
||||
end if parent_resource.actions.include?(:create)
|
||||
|
@ -1210,6 +1212,8 @@ module ActionDispatch
|
|||
resource_scope(:resources, Resource.new(resources.pop, options)) do
|
||||
yield if block_given?
|
||||
|
||||
concerns(options[:concerns]) if options[:concerns]
|
||||
|
||||
collection do
|
||||
get :index if parent_resource.actions.include?(:index)
|
||||
post :create if parent_resource.actions.include?(:create)
|
||||
|
@ -1580,15 +1584,33 @@ module ActionDispatch
|
|||
end
|
||||
end
|
||||
|
||||
module Concerns
|
||||
def concern(name, &block)
|
||||
@concerns[name] = block
|
||||
end
|
||||
|
||||
def concerns(*names)
|
||||
names.flatten.each do |name|
|
||||
if concern = @concerns[name]
|
||||
instance_eval(&concern)
|
||||
else
|
||||
raise ArgumentError, "No concern named #{name} was found!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(set) #:nodoc:
|
||||
@set = set
|
||||
@scope = { :path_names => @set.resources_path_names }
|
||||
@concerns = {}
|
||||
end
|
||||
|
||||
include Base
|
||||
include HttpHelpers
|
||||
include Redirection
|
||||
include Scoping
|
||||
include Concerns
|
||||
include Resources
|
||||
end
|
||||
end
|
||||
|
|
94
actionpack/test/dispatch/routing/concerns_test.rb
Normal file
94
actionpack/test/dispatch/routing/concerns_test.rb
Normal file
|
@ -0,0 +1,94 @@
|
|||
require 'abstract_unit'
|
||||
|
||||
class CommentsController < ActionController::Base
|
||||
def index
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
class ImageAttachmentsController < ActionController::Base
|
||||
def index
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
class RoutingConcernsTest < ActionDispatch::IntegrationTest
|
||||
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
|
||||
app.draw do
|
||||
concern :commentable do
|
||||
resources :comments
|
||||
end
|
||||
|
||||
concern :image_attachable do
|
||||
resources :image_attachments, only: :index
|
||||
end
|
||||
|
||||
resources :posts, concerns: [:commentable, :image_attachable] do
|
||||
resource :video, concerns: :commentable
|
||||
end
|
||||
|
||||
resource :picture, concerns: :commentable do
|
||||
resources :posts, concerns: :commentable
|
||||
end
|
||||
|
||||
scope "/videos" do
|
||||
concerns :commentable
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include Routes.url_helpers
|
||||
def app; Routes end
|
||||
|
||||
def test_accessing_concern_from_resources
|
||||
get "/posts/1/comments"
|
||||
assert_equal "200", @response.code
|
||||
assert_equal "/posts/1/comments", post_comments_path(post_id: 1)
|
||||
end
|
||||
|
||||
def test_accessing_concern_from_resource
|
||||
get "/picture/comments"
|
||||
assert_equal "200", @response.code
|
||||
assert_equal "/picture/comments", picture_comments_path
|
||||
end
|
||||
|
||||
def test_accessing_concern_from_nested_resource
|
||||
get "/posts/1/video/comments"
|
||||
assert_equal "200", @response.code
|
||||
assert_equal "/posts/1/video/comments", post_video_comments_path(post_id: 1)
|
||||
end
|
||||
|
||||
def test_accessing_concern_from_nested_resources
|
||||
get "/picture/posts/1/comments"
|
||||
assert_equal "200", @response.code
|
||||
assert_equal "/picture/posts/1/comments", picture_post_comments_path(post_id: 1)
|
||||
end
|
||||
|
||||
def test_accessing_concern_from_resources_with_more_than_one_concern
|
||||
get "/posts/1/image_attachments"
|
||||
assert_equal "200", @response.code
|
||||
assert_equal "/posts/1/image_attachments", post_image_attachments_path(post_id: 1)
|
||||
end
|
||||
|
||||
def test_accessing_concern_from_resources_using_only_option
|
||||
get "/posts/1/image_attachment/1"
|
||||
assert_equal "404", @response.code
|
||||
end
|
||||
|
||||
def test_accessing_concern_from_a_scope
|
||||
get "/videos/comments"
|
||||
assert_equal "200", @response.code
|
||||
end
|
||||
|
||||
def test_with_an_invalid_concern_name
|
||||
e = assert_raise ArgumentError do
|
||||
ActionDispatch::Routing::RouteSet.new.tap do |app|
|
||||
app.draw do
|
||||
resources :posts, concerns: :foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "No concern named foo was found!", e.message
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue