Skip to content

Commit

Permalink
resources_controller: added specs for when you want to find_by_(somet…
Browse files Browse the repository at this point in the history
…hing other than id) (users,

  addresses, interests)
  
  Fixed a bug where the resource mapping was using name instead of segment to
  match when a map should be used (this meant mapping didn't work for non 
  singleton resources)
  
  Thanks to Inviz <invi...@gmail.com> and Matt Mower <matt.mo...@gmail.com> 
  in http://groups.google.com/group/resources_controller/browse_thread/thread/b71b2ce196a09d15
  for the bug reports


git-svn-id: https://svn.ardes.com/rails_plugins/resources_controller@453 845bbffb-5c18-0410-91b3-f25c072b94c1
  • Loading branch information
ian committed Oct 12, 2007
1 parent 6bf2334 commit e8fc191
Show file tree
Hide file tree
Showing 9 changed files with 652 additions and 178 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG
@@ -1,3 +1,14 @@
* added specs for when you want to find_by_(something other than id) (users,
addresses, interests)

Fixed a bug where the resource mapping was using name instead of segment to
match when a map should be used (this meant mapping didn't work for non
singleton resources)

Thanks to Inviz <invi...@gmail.com> and Matt Mower <matt.mo...@gmail.com>
in http://groups.google.com/group/resources_controller/browse_thread/thread/b71b2ce196a09d15
for the bug reports

* Updated actions to be more in line with recent rails scaffold [Jason Lee <jlsync@gmail.com>]

* resources_controller now uses before_filter (instead of prepend_before_filter)
Expand Down
140 changes: 103 additions & 37 deletions SPECDOC
Expand Up @@ -129,64 +129,61 @@ Requesting /admin/forums/1 using XHR DELETE
- should call destroy on the found forum
- should render destroy.rjs

Routing shortcuts for Addresses (users/2/addresses/1) should map
- resources_path to /users/2/addresses
- resource_path to /users/2/addresses/1
- resource_path(9) to /users/2/addresses/9
- edit_resource_path to /users/2/addresses/1/edit
- edit_resource_path(9) to /users/2/addresses/9/edit
- new_resource_path to /users/2/addresses/new
Routing shortcuts for Addresses (users/dave/addresses/1) should map
- resources_path to /users/dave/addresses
- resource_path to /users/dave/addresses/1
- resource_path(9) to /users/dave/addresses/9
- edit_resource_path to /users/dave/addresses/1/edit
- edit_resource_path(9) to /users/dave/addresses/9/edit
- new_resource_path to /users/dave/addresses/new

resource_service in AddressesController
- should build new address with @user foreign key with new
- should find @address with find(@address.id)
- should raise RecordNotFound with find(@other_address.id)
- should find only addresses belonging to @user with find(:all)

Requesting /users/2/addresses
Requesting /users/dave/addresses
- should find the user
- should assign the found user for the view
- should assign the user_addresses association as the addresses resource_service

Requesting /users/foo/addresses (testing non-integer ids)
- should try and find user with id == 'foo'

Requesting /users/2/addresses using GET
Requesting /users/dave/addresses using GET
- should be successful
- should render index.rhtml
- should find all addresses
- should assign the found addresses for the view

Requesting /users/2/addresses/1 using GET
Requesting /users/dave/addresses/1 using GET
- should be successful
- should render show.rhtml
- should find the thing requested
- should assign the found thing for the view

Requesting /users/2/addresses/new using GET
Requesting /users/dave/addresses/new using GET
- should be successful
- should render new.rhtml
- should create an new thing
- should not save the new thing
- should assign the new thing for the view

Requesting /users/2/addresses/1/edit using GET
Requesting /users/dave/addresses/1/edit using GET
- should be successful
- should render edit.rhtml
- should find the thing requested
- should assign the found Thing for the view

Requesting /users/2/addresses using POST
Requesting /users/dave/addresses using POST
- should create a new address
- should redirect to the new address

Requesting /users/2/addresses/1 using PUT
Requesting /users/dave/addresses/1 using PUT
- should find the address requested
- should update the found address
- should assign the found address for the view
- should redirect to the address

Requesting /users/2/addresses/1 using DELETE
Requesting /users/dave/addresses/1 using DELETE
- should find the address requested
- should call destroy on the found thing
- should redirect to the things list
Expand Down Expand Up @@ -471,21 +468,21 @@ Requesting /forums/1/interests using GET
- should assign the found forum as :interested_in for the view
- should assign the forum_interests association as the interests resource_service

Routing shortcuts for Interests via User (users/1/interests/2) should map
- resources_path to /users/1/interests
- resource_path to /users/1/interests/2
- resource_path(9) to /users/1/interests/9
- edit_resource_path to /users/1/interests/2/edit
- edit_resource_path(9) to /users/1/interests/9/edit
- new_resource_path to /users/1/interests/new
Routing shortcuts for Interests via User (users/dave/interests/2) should map
- resources_path to /users/dave/interests
- resource_path to /users/dave/interests/2
- resource_path(9) to /users/dave/interests/9
- edit_resource_path to /users/dave/interests/2/edit
- edit_resource_path(9) to /users/dave/interests/9/edit
- new_resource_path to /users/dave/interests/new

resource_service in InterestsController via Forum
- should build new interest with @user fk and type with new
- should find @interest with find(@interest.id)
- should raise RecordNotFound with find(@other_interest.id)
- should find only interests belonging to @user with find(:all)

Requesting /users/1/interests using GET
Requesting /users/dave/interests using GET
- should find the user
- should assign the found user as :interested_in for the view
- should assign the user_interests association as the interests resource_service
Expand Down Expand Up @@ -650,27 +647,96 @@ Requesting /forums/1/tags/new using GET
- should assign the new tag for the view
- should send :resource= to controller with @tag

Routing shortcuts for Tags via User and Address (users/1/addresses/2/tags/3) should map
- resources_path to /users/1/addresses/2/tags
- resource_path to /users/1/addresses/2/tags/3
- resource_path(9) to /users/1/addresses/2/tags/9
- edit_resource_path to /users/1/addresses/2/tags/3/edit
- edit_resource_path(9) to /users/1/addresses/2/tags/9/edit
- new_resource_path to /users/1/addresses/2/tags/new
- enclosing_resource_path to /users/1/addresses/2
Routing shortcuts for Tags via User and Address (users/dave/addresses/2/tags/3) should map
- resources_path to /users/dave/addresses/2/tags
- resource_path to /users/dave/addresses/2/tags/3
- resource_path(9) to /users/dave/addresses/2/tags/9
- edit_resource_path to /users/dave/addresses/2/tags/3/edit
- edit_resource_path(9) to /users/dave/addresses/2/tags/9/edit
- new_resource_path to /users/dave/addresses/2/tags/new
- enclosing_resource_path to /users/dave/addresses/2

resource_service in TagsController via User and Address
- should build new tag with @address fk and type with new
- should find @tag with find(@tag.id)
- should raise RecordNotFound with find(@other_tag.id)
- should find only tags belonging to @address with find(:all)

Requesting /users/1/addresses/2/tags using GET
Requesting /users/dave/addresses/2/tags using GET
- should find the user
- should find the address
- should assign the found address for the view
- should assign the address_tags association as the tags resource_service

UsersController#route_for
- should map { :controller => 'users', :action => 'index' } to /users
- should map { :controller => 'users', :action => 'new' } to /users/new
- should map { :controller => 'users', :action => 'show', :id => 'dave' } to /users/dave
- should map { :controller => 'users', :action => 'edit', :id => 'dave' } to /users/dave/edit
- should map { :controller => 'users', :action => 'update', :id => 'dave'} to /users/dave
- should map { :controller => 'users', :action => 'destroy', :id => 'dave'} to /users/dave

UsersController#params_from
- should generate params { :controller => 'users', action => 'index' } from GET /users
- should generate params { :controller => 'users', action => 'new' } from GET /users/new
- should generate params { :controller => 'users', action => 'create' } from POST /users
- should generate params { :controller => 'users', action => 'show', id => '1' } from GET /users/dave
- should generate params { :controller => 'users', action => 'edit', id => '1' } from GET /users/dave;edit
- should generate params { :controller => 'users', action => 'update', id => '1' } from PUT /users/dave
- should generate params { :controller => 'users', action => 'destroy', id => '1' } from DELETE /users/dave

UsersController handling GET /users
- should be successful
- should render index template
- should find all users
- should assign the found users for the view

UsersControllerhandling GET /users.xml
- should be successful
- should find all users
- should render the found users as xml

UsersController handling GET /users/dave
- should be successful
- should render show template
- should find the user requested
- should assign the found user for the view

UsersControllerhandling GET /users/dave.xml
- should be successful
- should find the user requested
- should render the found user as xml

UsersController handling GET /users/new
- should be successful
- should render new template
- should create an new user
- should not save the new user
- should assign the new user for the view

UsersController handling GET /users/dave/edit
- should be successful
- should render edit template
- should find the user requested
- should assign the found User for the view

UsersController handling POST /users
- should create a new user
- should redirect to the new user on successful save
- should re-render 'new' on failed save

UsersController handling PUT /users/dave
- should find the user requested
- should update the found user
- should assign the found user for the view
- should redirect to the user on successful update
- should re-render 'edit' on failed update

UsersController handling DELETE /users/dave
- should find the user requested
- should call destroy on the found user
- should redirect to the users list

ActionView with resources_controller Helper
- should forward #resource_name to controller
- should forward #resources_name to controller
Expand Down Expand Up @@ -702,6 +768,6 @@ ResourcesController#route_resource_names (route_name:tag, :singleton:false)
- :account_info_tags should be [["account", true], ["info", true]]
- :new_account_info_tag should be [["account", true], ["info", true]]

Finished in 3.999181 seconds
Finished in 4.40074 seconds

493 examples, 0 failures
539 examples, 0 failures
69 changes: 65 additions & 4 deletions lib/ardes/resources_controller.rb
Expand Up @@ -294,6 +294,66 @@ module Ardes#:nodoc:
#
# When this controller is invoked of /things the :order_by_ids message will be sent to the Thing class,
# when it's invoked by /foos/1/things, then :order_by_ids message will be send to Foo.find(1).things association
#
# === using non standard ids
#
# Lets say you want to set to_param to login, and use find_by_login
# for your users in your URLs, with routes as follows:
#
# map.reosurces :users do |user|
# user.resources :addresses
# end
#
# First, the users controller needs to find reosurces using find_by_login
#
# class UsersController < ApplicationController
# resources_controller_for :users
#
# protected
# def find_resource(id = params[:id])
# resource_service.find_by_login(id)
# end
# end
#
# This controller will find users (for editing, showing, and destroying) as
# directed. (this controller will work for any route where user is the
# last resource, including the /users/dave route)
#
# Now you need to specify that the user as enclosing resource needs to be found
# with find_by_login. For the addresses case above, you would do this:
#
# class AddressesController < ApplicationController
# resources_controller_for :addresses
# nested_in :user do
# User.find_by_login(params[:user_id])
# end
# end
#
# If you wanted to open up more nested resources under user, you could repeat
# this specification in all such controllers, alternatively, you could map the
# resource in the ApplicationController, which would be usable by any controller
#
# If you know that user is never nested (i.e. /users/dave/addresses), then do this:
#
# class ApplicationController < ActionController::Base
# map_resource :user do
# User.find(params[:user_id])
# end
# end
#
# or, if user is sometimes nested (i.e. /forums/1/users/dave/addresses), do this:
#
# map_resource :user do
# ((enclosing_resource && enclosing_resource.users) || User).find(params[:user_id])
# end
#
# Your Addresses controller will now be the very simple one, and the resource map will
# load user as specified when it is hit by a route /users/dave/addresses.
#
# class AddressesController < ApplicationController
# resources_controller_for :addresses
# end
#
module ResourcesController
def self.extended(base)
base.class_eval do
Expand Down Expand Up @@ -402,7 +462,8 @@ def deprecated_resources_controller_for(options)
#
# See Specification#new for details of how to call this
def map_resource(name, options = {}, &block)
resource_specification_map[name.to_s] = Specification.new(name, options, &block)
spec = Specification.new(name, options, &block)
resource_specification_map[spec.segment] = spec
end

module ClassMethods
Expand Down Expand Up @@ -610,10 +671,10 @@ def load_wildcards(to_spec)
return if to_spec == '*'
route_resource_names.slice(enclosing_resources.size..-1).each do |segment, singleton|
return if to_spec && to_spec.segment == segment
name = singleton ? segment : segment.singularize
if resource_specification_map[name]
resource_specification_map[name].load_into(self)
if resource_specification_map[segment]
resource_specification_map[segment].load_into(self)
else
name = singleton ? segment : segment.singularize
Specification.new(name, :singleton => singleton).load_into(self)
end
end
Expand Down
14 changes: 7 additions & 7 deletions lib/ardes/resources_controller/specification.rb
Expand Up @@ -41,13 +41,13 @@ def self.new(name, options = {}, &block)
# Passing a block is the same as passing :find => Proc
def initialize(spec_name, options = {}, &block)
options.assert_valid_keys(:class, :source, :key, :find, :name_prefix, :segment)
@name = spec_name.to_s
@find = block || options.delete(:find)
@segment = options[:segment] || name.pluralize
@source = (options[:source] && options[:source].to_s) || name.pluralize
@name_prefix = options[:name_prefix] || (options[:name_prefix] == false ? '' : "#{name}_")
@klass = options[:class] || ((source && source.classify) || name.camelize).constantize
@key = options[:key] || name.foreign_key
@name = spec_name.to_s
@find = block || options.delete(:find)
@segment = (options[:segment] && options[:segment].to_s) || name.pluralize
@source = (options[:source] && options[:source].to_s) || name.pluralize
@name_prefix = options[:name_prefix] || (options[:name_prefix] == false ? '' : "#{name}_")
@klass = options[:class] || ((source && source.classify) || name.camelize).constantize
@key = (options[:key] && options[:key].to_s) || name.foreign_key
end

# returns false
Expand Down

0 comments on commit e8fc191

Please sign in to comment.