Permalink
Browse files

Wrap everything before new release.

  • Loading branch information...
1 parent 58b27b0 commit 5bba068ce745341bdb9661e133e363df3a7fc8e3 @josevalim committed Sep 1, 2009
View
@@ -1,3 +1,9 @@
+# Version 0.9
+
+* Backported ActionController::Responder from Rails 3;
+* Added parent_url helper;
+* Added association_chain helper (as suggested by http://github.com/emmanuel);
+
# Version 0.8
* Fixed a small bug on optional belongs to with namespaced controllers.
@@ -2,12 +2,7 @@ Inherited Resources
License: MIT
Version: 0.9.0
-You can also read this README in pretty html at the GitHub project Wiki page:
-
- http://wiki.github.com/josevalim/inherited_resources
-
-Description
------------
+== Description
Inherited Resources speeds up development by making your controllers inherit
all restful actions so you just have to focus on what is important. It makes
@@ -20,8 +15,7 @@ Inherited Resources is tested and compatible with Rails 2.2.x and Rails 2.3.x.
keywords: resources, controller, singleton, belongs_to, polymorphic, named_scope and I18n
-Installation
-------------
+== Installation
Install Inherited Resources is very easy. It is stored in GitHub, so just run
the following:
@@ -33,8 +27,7 @@ If you want it as plugin, just do:
script/plugin install git://github.com/josevalim/inherited_resources.git
-Basic Usage
------------
+== Basic Usage
To use Inherited Resources you just have to inherit (duh) it:
@@ -92,8 +85,7 @@ call inherit_resources in your controller class scope:
inherit_resources
end
-Overwriting defaults
---------------------
+== Overwriting defaults
Whenever you inherit from InheritedResources, several defaults are assumed.
For example you can have an AccountsController to account management while the
@@ -146,8 +138,7 @@ You can deal with it just doing:
end
end
-Overwriting actions
--------------------
+== Overwriting actions
Let's suppose that after destroying a project you want to redirect to your
root url instead of redirecting to projects url. You just have to do:
@@ -228,8 +219,7 @@ give a block that expects two arguments, the first will be executed only in
success scenarios and the second in failure scenarios. You keep everything
clean and organized inside the same action.
-Some DSL
---------
+== Some DSL
For those DSL lovers, InheritedResources won't leave you alone. You can overwrite
your success/failure blocks straight from your class binding. For it, you just
@@ -247,8 +237,7 @@ And then you can rewrite the last example as:
end
end
-Flash messages and I18n
------------------------
+== Flash messages and I18n
Flash messages are powered by I18n api. It checks for messages in the following
order:
@@ -311,8 +300,7 @@ the messages will be checked in the following order:
flash.projects.create.notice
flash.actions.create.notice
-Has Scope
----------
+== Has Scope
InheritedResources tries to integrate nicely with your model. In order to do so,
it also is named_scope fluent. Let's suppose our Project model with the scopes:
@@ -352,8 +340,7 @@ per page. In such cases, you can give a proc as default value:
has_scope :limit, :default => proc{|c| c.session[:limit] || 10 }
-Belongs to
-----------
+== Belongs to
Finally, our Projects are going to get some Tasks. Then you create a
TasksController and do:
@@ -373,8 +360,7 @@ customize how InheritedResources find your projects:
It also accepts :route_name, :parent_class and :instance_name as options.
Check the lib/inherited_resources/class_methods.rb for more.
-Nested belongs to
------------------
+== Nested belongs to
Now, our Tasks get some Comments and you need to nest even deeper. Good
practices says that you should never nest more than two resources, but sometimes
@@ -401,8 +387,7 @@ Warning: calling several belongs_to is the same as nesting them:
In other words, the code above is the same as calling nested_belongs_to.
-Polymorphic belongs to
-----------------------
+== Polymorphic belongs to
We can go even further. Let's suppose our Projects can now have Files, Messages
and Tasks, and they are all commentable. In this case, the best solution is to
@@ -434,8 +419,7 @@ When using polymorphic associations, you get some free helpers:
parent_class #=> Task
parent #=> @task
-Optional belongs to
--------------------
+== Optional belongs to
Later you decide to create a view to show all comments, independent if they belong
to a task, file or message. You can reuse your polymorphic controller just doing:
@@ -460,8 +444,7 @@ are available. As you expect, when no parent is found, the helpers return:
parent_class #=> nil
parent #=> nil
-Singletons
-----------
+== Singletons
Now we are going to add manager to projects. We say that Manager is a singleton
resource because a Project has just one manager. You should declare it as
@@ -477,8 +460,7 @@ option.
It will deal with everything again and hide the action :index from you.
-URL Helpers
------------
+== URL Helpers
When you use InheritedResources it creates some URL helpers.
And they handle everything for you. :)
@@ -490,6 +472,7 @@ And they handle everything for you. :)
edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit
edit_resource_url(comment) #=> /posts/1/comments/#{comment.to_param}/edit
collection_url # => /posts/1/comments
+ parent_url # => /posts/1
# /projects/1/tasks
resource_url # => /projects/1/tasks/#{@task.to_param}
@@ -498,6 +481,7 @@ And they handle everything for you. :)
edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit
edit_resource_url(task) # => /projects/1/tasks/#{task.to_param}/edit
collection_url # => /projects/1/tasks
+ parent_url # => /projects/1
# /users
resource_url # => /users/#{@user.to_param}
@@ -506,6 +490,7 @@ And they handle everything for you. :)
edit_resource_url # => /users/#{@user.to_param}/edit
edit_resource_url(user) # => /users/#{user.to_param}/edit
collection_url # => /users
+ parent_url # => /
Those urls helpers also accepts a hash as options, just as in named routes.
View
@@ -14,7 +14,7 @@ begin
s.homepage = "http://github.com/josevalim/inherited_resources"
s.description = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important."
s.authors = ['José Valim']
- s.files = FileList["[A-Z]*", "{lib}/**/*"]
+ s.files = FileList["README.rdoc", "[A-Z]*", "{lib}/**/*"]
end
rescue LoadError
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
@@ -31,7 +31,7 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'InheritedResources'
rdoc.options << '--line-numbers' << '--inline-source'
- rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('MIT-LICENSE')
rdoc.rdoc_files.include('lib/**/*.rb')
end
@@ -25,7 +25,7 @@ def self.inherit_resources(base)
helper_method :collection_url, :collection_path, :resource_url, :resource_path,
:new_resource_url, :new_resource_path, :edit_resource_url, :edit_resource_path,
- :parent_url, :parent_path, :resource, :collection, :resource_class
+ :parent_url, :parent_path, :resource, :collection, :resource_class, :association_chain
base.with_options :instance_writer => false do |c|
c.class_inheritable_accessor :resource_class
@@ -82,6 +82,16 @@ def parent?
false
end
+ # Returns the association chain, with all parents (does not include the
+ # current resource).
+ #
+ def association_chain
+ @association_chain ||=
+ symbols_for_association_chain.inject([begin_of_association_chain]) do |chain, symbol|
+ chain << evaluate_parent(symbol, resources_configuration[symbol], chain.last)
+ end.compact.freeze
+ end
+
# Overwrite this method to provide other interpolation options when
# the flash message is going to be set.
#
@@ -103,16 +113,6 @@ def resource_instance_name #:nodoc:
self.resources_configuration[:self][:instance_name]
end
- # Returns the association chain, with all parents (does not include the
- # current resource).
- #
- def association_chain
- @association_chain ||=
- symbols_for_association_chain.inject([begin_of_association_chain]) do |chain, symbol|
- chain << evaluate_parent(symbol, resources_configuration[symbol], chain.last)
- end.compact.freeze
- end
-
# This methods gets your begin_of_association_chain, join it with your
# parents chain and returns the scoped association.
#
@@ -10,20 +10,23 @@ module InheritedResources
# new_resource_url # => /posts/1/comments/new
# edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit
# collection_url # => /posts/1/comments
+ # parent_url # => /posts/1
#
# # /projects/1/tasks
- # resource_url # => /products/1/tasks/#{@task.to_param}
- # resource_url(task) # => /products/1/tasks/#{task.to_param}
- # new_resource_url # => /products/1/tasks/new
- # edit_resource_url # => /products/1/tasks/#{@task.to_param}/edit
- # collection_url # => /products/1/tasks
+ # resource_url # => /projects/1/tasks/#{@task.to_param}
+ # resource_url(task) # => /projects/1/tasks/#{task.to_param}
+ # new_resource_url # => /projects/1/tasks/new
+ # edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit
+ # collection_url # => /projects/1/tasks
+ # parent_url # => /projects/1
#
# # /users
# resource_url # => /users/#{@user.to_param}
# resource_url(user) # => /users/#{user.to_param}
# new_resource_url # => /users/new
# edit_resource_url # => /users/#{@user.to_param}/edit
# collection_url # => /users
+ # parent_url # => /
#
# The nice thing is that those urls are not guessed during runtime. They are
# all created when you inherit.
@@ -0,0 +1,125 @@
+require File.dirname(__FILE__) + '/test_helper'
+
+class Pet
+ def self.human_name; 'Pet'; end
+end
+
+class Puppet
+ def self.human_name; 'Puppet'; end
+end
+
+class PetsController < InheritedResources::Base
+ attr_accessor :current_user
+
+ def edit
+ @pet = 'new pet'
+ edit!
+ end
+
+ protected
+ def collection
+ @pets ||= end_of_association_chain.all
+ end
+
+ def begin_of_association_chain
+ @current_user
+ end
+end
+
+class BeginOfAssociationChainTest < ActionController::TestCase
+ tests PetsController
+
+ def setup
+ @controller.current_user = mock()
+ end
+
+ def test_begin_of_association_chain_is_called_on_index
+ @controller.current_user.expects(:pets).returns(Pet)
+ Pet.expects(:all).returns(mock_pet)
+ get :index
+ assert_response :success
+ assert_equal 'Index HTML', @response.body.strip
+ end
+
+ def test_begin_of_association_chain_is_called_on_new
+ @controller.current_user.expects(:pets).returns(Pet)
+ Pet.expects(:build).returns(mock_pet)
+ get :new
+ assert_response :success
+ assert_equal 'New HTML', @response.body.strip
+ end
+
+ def test_begin_of_association_chain_is_called_on_show
+ @controller.current_user.expects(:pets).returns(Pet)
+ Pet.expects(:find).with('47').returns(mock_pet)
+ get :show, :id => '47'
+ assert_response :success
+ assert_equal 'Show HTML', @response.body.strip
+ end
+
+ def test_instance_variable_should_not_be_set_if_already_defined
+ @controller.current_user.expects(:pets).never
+ Pet.expects(:find).never
+ get :edit
+ assert_response :success
+ assert_equal 'new pet', assigns(:pet)
+ end
+
+ def test_model_is_not_initialized_with_nil
+ @controller.current_user.expects(:pets).returns(Pet)
+ Pet.expects(:build).with({}).returns(mock_pet)
+ get :new
+ assert_equal mock_pet, assigns(:pet)
+ end
+
+ def test_begin_of_association_chain_is_included_in_chain
+ @controller.current_user.expects(:pets).returns(Pet)
+ Pet.expects(:build).with({}).returns(mock_pet)
+ get :new
+ assert_equal [@controller.current_user], @controller.send(:association_chain)
+ end
+
+ protected
+ def mock_pet(stubs={})
+ @mock_pet ||= mock(stubs)
+ end
+
+end
+
+class PuppetsController < InheritedResources::Base
+ optional_belongs_to :pet
+end
+
+class AssociationChainTest < ActionController::TestCase
+ tests PuppetsController
+
+ def setup
+ @controller.stubs(:resource_url).returns('/')
+ @controller.stubs(:collection_url).returns('/')
+ end
+
+ def test_parent_is_added_to_association_chain
+ Pet.expects(:find).with('37').returns(mock_pet)
+ mock_pet.expects(:puppets).returns(Puppet)
+ Puppet.expects(:find).with('42').returns(mock_puppet)
+ mock_puppet.expects(:destroy)
+ delete :destroy, :id => '42', :pet_id => '37'
+ assert_equal [mock_pet], @controller.send(:association_chain)
+ end
+
+ def test_parent_is_added_to_association_chain_if_not_available
+ Puppet.expects(:find).with('42').returns(mock_puppet)
+ mock_puppet.expects(:destroy)
+ delete :destroy, :id => '42'
+ assert_equal [], @controller.send(:association_chain)
+ end
+
+ protected
+ def mock_pet(stubs={})
+ @mock_pet ||= mock(stubs)
+ end
+
+ def mock_puppet(stubs={})
+ @mock_puppet ||= mock(stubs)
+ end
+end
Oops, something went wrong. Retry.

0 comments on commit 5bba068

Please sign in to comment.