aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller/resources.rb104
1 files changed, 96 insertions, 8 deletions
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb
index b2174b3c9a..7ca9007072 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/resources.rb
@@ -18,26 +18,26 @@ module ActionController
end
def controller
- (options[:controller] || plural).to_s
+ @controller ||= (options[:controller] || plural).to_s
end
def path
- "#{path_prefix}/#{plural}"
+ @path ||= "#{path_prefix}/#{plural}"
end
def new_path
- "#{path}/new"
+ @new_path ||= "#{path}/new"
end
def member_path
- "#{path}/:id"
+ @member_path ||= "#{path}/:id"
end
def nesting_path_prefix
- "#{path}/:#{singular}_id"
+ @nesting_path_prefix ||= "#{path}/:#{singular}_id"
end
- private
+ protected
def arrange_actions
@collection_methods = arrange_actions_by_methods(options.delete(:collection))
@member_methods = arrange_actions_by_methods(options.delete(:member))
@@ -65,7 +65,34 @@ module ActionController
(collection[method] ||= []).unshift(action)
end
end
-
+
+ class SingletonResource < Resource #:nodoc:
+ def initialize(entity, options)
+ @singular = entity
+ @plural = options[:plural] || singular.to_s.pluralize
+
+ @options = options
+ arrange_actions
+ add_default_actions
+ set_prefixes
+ end
+
+ def controller
+ @controller ||= (options[:controller] || singular).to_s
+ end
+
+ def path
+ @path ||= "#{path_prefix}/#{singular}"
+ end
+
+ def new_path
+ nil
+ end
+
+ alias_method :member_path, :path
+ alias_method :nesting_path_prefix, :path
+ end
+
# Creates named routes for implementing verb-oriented controllers. This is
# useful for implementing REST API's, where a single resource has different
# behavior based on the HTTP verb (method) used to access it.
@@ -209,6 +236,55 @@ module ActionController
entities.each { |entity| map_resource entity, options.dup, &block }
end
+ # Creates named routes for implementing verb-oriented controllers for a singleton resource.
+ # A singleton resource is global to the current user visiting the application, such as a user's
+ # /account profile.
+ #
+ # See map.resources for general conventions. These are the main differences:
+ # - a singular name is given to map.resource. The default controller name is taken from the singular name.
+ # - To specify a custom plural name, use the :plural option. There is no :singular option
+ # - No default index, new, or create routes are created for the singleton resource controller.
+ # - When nesting singleton resources, only the singular name is used as the path prefix (example: 'account/messages/1')
+ #
+ # Example:
+ #
+ # map.resource :account
+ #
+ # class AccountController < ActionController::Base
+ # # GET account_url
+ # def show
+ # # find and return a specific message
+ # end
+ #
+ # # GET edit_account_url
+ # def edit
+ # # return an HTML form for editing a specific message
+ # end
+ #
+ # # PUT account_url
+ # def update
+ # # find and update a specific message
+ # end
+ #
+ # # DELETE account_url
+ # def destroy
+ # # delete a specific message
+ # end
+ # end
+ #
+ # Along with the routes themselves, #resource generates named routes for use in
+ # controllers and views. <tt>map.resource :account</tt> produces the following named routes and helpers:
+ #
+ # Named Route Helpers
+ # account account_url(id), hash_for_account_url(id),
+ # account_path(id), hash_for_account_path(id)
+ # edit_account edit_account_url(id), hash_for_edit_account_url(id),
+ # edit_account_path(id), hash_for_edit_account_path(id)
+ def resource(*entities, &block)
+ options = entities.last.is_a?(Hash) ? entities.pop : { }
+ entities.each { |entity| map_singleton_resource entity, options.dup, &block }
+ end
+
private
def map_resource(entities, options = {}, &block)
resource = Resource.new(entities, options)
@@ -224,6 +300,18 @@ module ActionController
end
end
+ def map_singleton_resource(entities, options = {}, &block)
+ resource = SingletonResource.new(entities, options)
+
+ with_options :controller => resource.controller do |map|
+ map_member_actions(map, resource)
+
+ if block_given?
+ with_options(:path_prefix => resource.singular, &block)
+ end
+ end
+ end
+
def map_collection_actions(map, resource)
resource.collection_methods.each do |method, actions|
route_options = requirements_for(method)
@@ -284,7 +372,7 @@ module ActionController
map.connect(resource.member_path, :action => "destroy", :conditions => { :method => :delete })
map.connect("#{resource.member_path}.:format", :action => "destroy", :conditions => { :method => :delete })
end
-
+
def requirements_for(method)
method == :any ? {} : { :conditions => { :method => method } }
end