josevalim-inherited_resources 0.3 → 0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +7 -0
- data/README +30 -1
- data/lib/inherited_resources/base.rb +1 -3
- data/lib/inherited_resources/belongs_to_helpers.rb +6 -30
- data/lib/inherited_resources/class_methods.rb +241 -4
- data/lib/inherited_resources/polymorphic_helpers.rb +47 -2
- data/lib/inherited_resources/url_helpers.rb +2 -1
- data/test/belongs_to_test.rb +66 -76
- data/test/class_methods_test.rb +111 -2
- data/test/optional_belongs_to_test.rb +190 -0
- data/test/polymorphic_test.rb +111 -0
- data/test/singleton_test.rb +83 -0
- data/test/url_helpers_test.rb +36 -4
- data/test/views/products/edit.html.erb +1 -0
- data/test/views/products/index.html.erb +1 -0
- data/test/views/products/new.html.erb +1 -0
- data/test/views/products/show.html.erb +1 -0
- metadata +10 -7
- data/lib/inherited_resources/belongs_to.rb +0 -227
- data/test/belongs_to_base_test.rb +0 -268
- data/test/polymorphic_base_test.rb +0 -282
- data/test/singleton_base_test.rb +0 -226
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class Factory; end
|
4
|
+
class Company; end
|
5
|
+
|
6
|
+
class Employee
|
7
|
+
def self.human_name; 'Employee'; end
|
8
|
+
end
|
9
|
+
|
10
|
+
class EmployeesController < InheritedResources::Base
|
11
|
+
belongs_to :factory, :company, :polymorphic => true
|
12
|
+
end
|
13
|
+
|
14
|
+
class PolymorphicTest < TEST_CLASS
|
15
|
+
|
16
|
+
def setup
|
17
|
+
@controller = EmployeesController.new
|
18
|
+
@controller.request = @request = ActionController::TestRequest.new
|
19
|
+
@controller.response = @response = ActionController::TestResponse.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_expose_all_employees_as_instance_variable_on_index
|
23
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
24
|
+
mock_factory.expects(:employees).returns(Employee)
|
25
|
+
Employee.expects(:find).with(:all).returns([mock_employee])
|
26
|
+
get :index, :factory_id => '37'
|
27
|
+
assert_equal mock_factory, assigns(:factory)
|
28
|
+
assert_equal [mock_employee], assigns(:employees)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_expose_the_resquested_employee_on_show
|
32
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
33
|
+
mock_factory.expects(:employees).returns(Employee)
|
34
|
+
Employee.expects(:find).with('42').returns(mock_employee)
|
35
|
+
get :show, :id => '42', :factory_id => '37'
|
36
|
+
assert_equal mock_factory, assigns(:factory)
|
37
|
+
assert_equal mock_employee, assigns(:employee)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_expose_a_new_employee_on_new
|
41
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
42
|
+
mock_factory.expects(:employees).returns(Employee)
|
43
|
+
Employee.expects(:build).returns(mock_employee)
|
44
|
+
get :new, :factory_id => '37'
|
45
|
+
assert_equal mock_factory, assigns(:factory)
|
46
|
+
assert_equal mock_employee, assigns(:employee)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_expose_the_resquested_employee_on_edit
|
50
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
51
|
+
mock_factory.expects(:employees).returns(Employee)
|
52
|
+
Employee.expects(:find).with('42').returns(mock_employee)
|
53
|
+
get :edit, :id => '42', :factory_id => '37'
|
54
|
+
assert_equal mock_factory, assigns(:factory)
|
55
|
+
assert_equal mock_employee, assigns(:employee)
|
56
|
+
assert_response :success
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_expose_a_newly_create_employee_on_create
|
60
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
61
|
+
mock_factory.expects(:employees).returns(Employee)
|
62
|
+
Employee.expects(:build).with({'these' => 'params'}).returns(mock_employee(:save => true))
|
63
|
+
post :create, :factory_id => '37', :employee => {:these => 'params'}
|
64
|
+
assert_equal mock_factory, assigns(:factory)
|
65
|
+
assert_equal mock_employee, assigns(:employee)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_update_the_requested_object_on_update
|
69
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
70
|
+
mock_factory.expects(:employees).returns(Employee)
|
71
|
+
Employee.expects(:find).with('42').returns(mock_employee)
|
72
|
+
mock_employee.expects(:update_attributes).with({'these' => 'params'}).returns(true)
|
73
|
+
put :update, :id => '42', :factory_id => '37', :employee => {:these => 'params'}
|
74
|
+
assert_equal mock_factory, assigns(:factory)
|
75
|
+
assert_equal mock_employee, assigns(:employee)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_the_resquested_employee_is_destroyed_on_destroy
|
79
|
+
Factory.expects(:find).with('37').returns(mock_factory)
|
80
|
+
mock_factory.expects(:employees).returns(Employee)
|
81
|
+
Employee.expects(:find).with('42').returns(mock_employee)
|
82
|
+
mock_employee.expects(:destroy)
|
83
|
+
delete :destroy, :id => '42', :factory_id => '37'
|
84
|
+
assert_equal mock_factory, assigns(:factory)
|
85
|
+
assert_equal mock_employee, assigns(:employee)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_polymorphic_helpers
|
89
|
+
new_factory = Factory.new
|
90
|
+
Factory.expects(:find).with('37').returns(new_factory)
|
91
|
+
new_factory.expects(:employees).returns(Employee)
|
92
|
+
Employee.expects(:find).with(:all).returns([mock_employee])
|
93
|
+
get :index, :factory_id => '37'
|
94
|
+
|
95
|
+
assert @controller.send(:parent?)
|
96
|
+
assert_equal :factory, assigns(:parent_type)
|
97
|
+
assert_equal :factory, @controller.send(:parent_type)
|
98
|
+
assert_equal Factory, @controller.send(:parent_class)
|
99
|
+
assert_equal new_factory, assigns(:factory)
|
100
|
+
assert_equal new_factory, @controller.send(:parent)
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
def mock_factory(stubs={})
|
105
|
+
@mock_factory ||= mock(stubs)
|
106
|
+
end
|
107
|
+
|
108
|
+
def mock_employee(stubs={})
|
109
|
+
@mock_employee ||= mock(stubs)
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
# This test file is instead to test the how controller flow and actions
|
4
|
+
# using a belongs_to association. This is done using mocks a la rspec.
|
5
|
+
#
|
6
|
+
class Store
|
7
|
+
end
|
8
|
+
|
9
|
+
class Manager
|
10
|
+
def self.human_name; 'Manager'; end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ManagersController < InheritedResources::Base
|
14
|
+
belongs_to :store, :singleton => true
|
15
|
+
end
|
16
|
+
|
17
|
+
class SingletonTest < TEST_CLASS
|
18
|
+
|
19
|
+
def setup
|
20
|
+
@controller = ManagersController.new
|
21
|
+
@controller.request = @request = ActionController::TestRequest.new
|
22
|
+
@controller.response = @response = ActionController::TestResponse.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_expose_the_resquested_manager_on_show
|
26
|
+
Store.expects(:find).with('37').returns(mock_store)
|
27
|
+
mock_store.expects(:manager).returns(mock_manager)
|
28
|
+
get :show, :store_id => '37'
|
29
|
+
assert_equal mock_store, assigns(:store)
|
30
|
+
assert_equal mock_manager, assigns(:manager)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_expose_a_new_manager_on_new
|
34
|
+
Store.expects(:find).with('37').returns(mock_store)
|
35
|
+
mock_store.expects(:build_manager).returns(mock_manager)
|
36
|
+
get :new, :store_id => '37'
|
37
|
+
assert_equal mock_store, assigns(:store)
|
38
|
+
assert_equal mock_manager, assigns(:manager)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_expose_the_resquested_manager_on_edit
|
42
|
+
Store.expects(:find).with('37').returns(mock_store)
|
43
|
+
mock_store.expects(:manager).returns(mock_manager)
|
44
|
+
get :edit, :store_id => '37'
|
45
|
+
assert_equal mock_store, assigns(:store)
|
46
|
+
assert_equal mock_manager, assigns(:manager)
|
47
|
+
assert_response :success
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_expose_a_newly_create_manager_on_create
|
51
|
+
Store.expects(:find).with('37').returns(mock_store)
|
52
|
+
mock_store.expects(:build_manager).with({'these' => 'params'}).returns(mock_manager(:save => true))
|
53
|
+
post :create, :store_id => '37', :manager => {:these => 'params'}
|
54
|
+
assert_equal mock_store, assigns(:store)
|
55
|
+
assert_equal mock_manager, assigns(:manager)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_update_the_requested_object_on_update
|
59
|
+
Store.expects(:find).with('37').returns(mock_store(:manager => mock_manager))
|
60
|
+
mock_manager.expects(:update_attributes).with({'these' => 'params'}).returns(true)
|
61
|
+
put :update, :store_id => '37', :manager => {:these => 'params'}
|
62
|
+
assert_equal mock_store, assigns(:store)
|
63
|
+
assert_equal mock_manager, assigns(:manager)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_the_resquested_manager_is_destroyed_on_destroy
|
67
|
+
Store.expects(:find).with('37').returns(mock_store)
|
68
|
+
mock_store.expects(:manager).returns(mock_manager)
|
69
|
+
mock_manager.expects(:destroy)
|
70
|
+
delete :destroy, :store_id => '37'
|
71
|
+
assert_equal mock_store, assigns(:store)
|
72
|
+
assert_equal mock_manager, assigns(:manager)
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
def mock_store(stubs={})
|
77
|
+
@mock_store ||= mock(stubs)
|
78
|
+
end
|
79
|
+
|
80
|
+
def mock_manager(stubs={})
|
81
|
+
@mock_manager ||= mock(stubs)
|
82
|
+
end
|
83
|
+
end
|
data/test/url_helpers_test.rb
CHANGED
@@ -30,7 +30,7 @@ end
|
|
30
30
|
|
31
31
|
class Bed; end
|
32
32
|
class BedsController < InheritedResources::Base
|
33
|
-
belongs_to :house, :building, :polymorphic => true
|
33
|
+
belongs_to :house, :building, :polymorphic => true, :optional => true
|
34
34
|
end
|
35
35
|
|
36
36
|
class Dish; end
|
@@ -182,7 +182,7 @@ class UrlHelpersTest < ActiveSupport::TestCase
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
-
def
|
185
|
+
def test_url_helpers_on_singletons_with_belongs_to
|
186
186
|
controller = OwnersController.new
|
187
187
|
controller.instance_variable_set('@house', :house)
|
188
188
|
controller.instance_variable_set('@owner', :owner)
|
@@ -204,7 +204,7 @@ class UrlHelpersTest < ActiveSupport::TestCase
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
-
def
|
207
|
+
def test_url_helpers_on_polymorphic_belongs_to
|
208
208
|
house = House.new
|
209
209
|
bed = Bed.new
|
210
210
|
|
@@ -277,7 +277,7 @@ class UrlHelpersTest < ActiveSupport::TestCase
|
|
277
277
|
end
|
278
278
|
|
279
279
|
def test_url_helpers_on_singleton_nested_polymorphic_belongs_to
|
280
|
-
#
|
280
|
+
# This must not be usefull in singleton controllers...
|
281
281
|
# Center.new
|
282
282
|
house = House.new
|
283
283
|
table = Table.new
|
@@ -308,4 +308,36 @@ class UrlHelpersTest < ActiveSupport::TestCase
|
|
308
308
|
end
|
309
309
|
end
|
310
310
|
|
311
|
+
def test_url_helpers_on_optional_polymorphic_belongs_to
|
312
|
+
bed = Bed.new
|
313
|
+
new_bed = Bed.new
|
314
|
+
Bed.stubs(:new).returns(new_bed)
|
315
|
+
new_bed.stubs(:new_record?).returns(true)
|
316
|
+
|
317
|
+
controller = BedsController.new
|
318
|
+
controller.instance_variable_set('@parent_type', nil)
|
319
|
+
controller.instance_variable_set('@bed', bed)
|
320
|
+
|
321
|
+
[:url, :path].each do |path_or_url|
|
322
|
+
controller.expects("beds_#{path_or_url}").with().once
|
323
|
+
controller.send("collection_#{path_or_url}")
|
324
|
+
|
325
|
+
controller.expects("bed_#{path_or_url}").with(bed).once
|
326
|
+
controller.send("resource_#{path_or_url}")
|
327
|
+
|
328
|
+
controller.expects("new_bed_#{path_or_url}").with().once
|
329
|
+
controller.send("new_resource_#{path_or_url}")
|
330
|
+
|
331
|
+
controller.expects("edit_bed_#{path_or_url}").with(bed).once
|
332
|
+
controller.send("edit_resource_#{path_or_url}")
|
333
|
+
end
|
334
|
+
|
335
|
+
# Testing if it accepts args...
|
336
|
+
controller.expects("polymorphic_url").with([:arg]).once
|
337
|
+
controller.send("resource_url", :arg)
|
338
|
+
|
339
|
+
controller.expects("edit_polymorphic_url").with([:arg]).once
|
340
|
+
controller.send("edit_resource_url", :arg)
|
341
|
+
end
|
342
|
+
|
311
343
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Edit HTML
|
@@ -0,0 +1 @@
|
|
1
|
+
Index HTML
|
@@ -0,0 +1 @@
|
|
1
|
+
New HTML
|
@@ -0,0 +1 @@
|
|
1
|
+
Show HTML
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: josevalim-inherited_resources
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.4"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Jos\xC3\xA9 Valim"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-02-
|
12
|
+
date: 2009-02-15 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -30,7 +30,6 @@ files:
|
|
30
30
|
- lib/inherited_resources.rb
|
31
31
|
- lib/inherited_resources/base.rb
|
32
32
|
- lib/inherited_resources/base_helpers.rb
|
33
|
-
- lib/inherited_resources/belongs_to.rb
|
34
33
|
- lib/inherited_resources/belongs_to_helpers.rb
|
35
34
|
- lib/inherited_resources/class_methods.rb
|
36
35
|
- lib/inherited_resources/dumb_responder.rb
|
@@ -69,16 +68,16 @@ test_files:
|
|
69
68
|
- test/aliases_test.rb
|
70
69
|
- test/base_helpers_test.rb
|
71
70
|
- test/base_test.rb
|
72
|
-
- test/belongs_to_base_test.rb
|
73
71
|
- test/belongs_to_test.rb
|
74
72
|
- test/class_methods_test.rb
|
75
|
-
- test/fixtures/en.yml
|
76
73
|
- test/nested_belongs_to_test.rb
|
77
|
-
- test/
|
74
|
+
- test/optional_belongs_to_test.rb
|
75
|
+
- test/polymorphic_test.rb
|
78
76
|
- test/respond_to_test.rb
|
79
|
-
- test/
|
77
|
+
- test/singleton_test.rb
|
80
78
|
- test/test_helper.rb
|
81
79
|
- test/url_helpers_test.rb
|
80
|
+
- test/fixtures/en.yml
|
82
81
|
- test/views/cities/edit.html.erb
|
83
82
|
- test/views/cities/index.html.erb
|
84
83
|
- test/views/cities/new.html.erb
|
@@ -95,6 +94,10 @@ test_files:
|
|
95
94
|
- test/views/managers/new.html.erb
|
96
95
|
- test/views/managers/show.html.erb
|
97
96
|
- test/views/pets/edit.html.erb
|
97
|
+
- test/views/products/edit.html.erb
|
98
|
+
- test/views/products/index.html.erb
|
99
|
+
- test/views/products/new.html.erb
|
100
|
+
- test/views/products/show.html.erb
|
98
101
|
- test/views/professors/edit.html.erb
|
99
102
|
- test/views/professors/index.html.erb
|
100
103
|
- test/views/professors/new.html.erb
|
@@ -1,227 +0,0 @@
|
|
1
|
-
# = belongs_to
|
2
|
-
#
|
3
|
-
# This allows you to specify to belongs_to in your controller. You might use
|
4
|
-
# this when you are having nested resources in your routes:
|
5
|
-
#
|
6
|
-
# class TasksController < InheritedResources::Base
|
7
|
-
# belongs_to :project
|
8
|
-
# end
|
9
|
-
#
|
10
|
-
# This will do all magic assuming some defaults. It assumes that your URL to
|
11
|
-
# access those tasks are:
|
12
|
-
#
|
13
|
-
# /projects/:project_id/tasks
|
14
|
-
#
|
15
|
-
# But all defaults are configurable. The options are:
|
16
|
-
#
|
17
|
-
# * :parent_class => Allows you to specify what is the parent class.
|
18
|
-
#
|
19
|
-
# belongs_to :project, :parent_class => AdminProject
|
20
|
-
#
|
21
|
-
# * :class_name => Also allows you to specify the parent class, but you should
|
22
|
-
# give a string. Added for ActiveRecord belongs to compatibility.
|
23
|
-
#
|
24
|
-
# * :instance_name => How this object will appear in your views. In this case
|
25
|
-
# the default is @project. Overwrite it with a symbol.
|
26
|
-
#
|
27
|
-
# belongs_to :project, :instance_name => :my_project
|
28
|
-
#
|
29
|
-
# * :finder => Specifies which method should be called to instantiate the
|
30
|
-
# parent. Let's suppose you are using slugs ("this-is-project-title") in URLs
|
31
|
-
# so your tasks url would be: "projects/this-is-project-title/tasks". Then you
|
32
|
-
# should do this in your TasksController:
|
33
|
-
#
|
34
|
-
# belongs_to :project, :finder => :find_by_title!
|
35
|
-
#
|
36
|
-
# This will make your projects be instantiated as:
|
37
|
-
#
|
38
|
-
# Project.find_by_title!(params[:project_id])
|
39
|
-
#
|
40
|
-
# Instead of:
|
41
|
-
#
|
42
|
-
# Project.find(params[:project_id])
|
43
|
-
#
|
44
|
-
# * param => Allows you to specify params key used to instantiate the parent.
|
45
|
-
# Default is :parent_id, which in this case is :project_id.
|
46
|
-
#
|
47
|
-
# * route_name => Allows you to specify what is the route name in your url
|
48
|
-
# helper. By default is 'project'. But if your url helper should be
|
49
|
-
# "admin_project_task_url" instead of "project_task_url", just do:
|
50
|
-
#
|
51
|
-
# belongs_to :project, :route_name => "admin_project"
|
52
|
-
#
|
53
|
-
# = nested_belongs_to
|
54
|
-
#
|
55
|
-
# If for some reason you need to nested more than two resources, you can do:
|
56
|
-
#
|
57
|
-
# class TasksController
|
58
|
-
# belongs_to :company, :project
|
59
|
-
# end
|
60
|
-
#
|
61
|
-
# ATTENTION! This DOES NOT mean polymorphic associations as in resource_controller.
|
62
|
-
# Polymorphic associations are not supported yet.
|
63
|
-
#
|
64
|
-
# It means that companies have many projects which have many tasks. You URL
|
65
|
-
# should be:
|
66
|
-
#
|
67
|
-
# /companies/:company_id/projects/:project_id/tasks/:id
|
68
|
-
#
|
69
|
-
# Everything will be handled for you again. And all defaults will describe above
|
70
|
-
# will be assumed. But if you have to change the defaults. You will have to
|
71
|
-
# specify one association by one:
|
72
|
-
#
|
73
|
-
# class TasksController
|
74
|
-
# belongs_to :company, :finder => :find_by_name!, :param => :company_name
|
75
|
-
# belongs_to :project
|
76
|
-
# end
|
77
|
-
#
|
78
|
-
# belongs_to is aliased as nested_belongs_to, so this provides a nicer syntax:
|
79
|
-
#
|
80
|
-
# class TasksController
|
81
|
-
# nested_belongs_to :company, :finder => :find_by_name!, :param => :company_name
|
82
|
-
# nested_belongs_to :project
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# In this case the association chain would be:
|
86
|
-
#
|
87
|
-
# Company.find_by_name!(params[:company_name]).projects.find(params[:project_id]).tasks.find(:all)
|
88
|
-
#
|
89
|
-
# When you are using nested resources, you have one more option to config.
|
90
|
-
# Let's suppose that to get all projects from a company, you have to do:
|
91
|
-
#
|
92
|
-
# Company.admin_projects
|
93
|
-
#
|
94
|
-
# Instead of:
|
95
|
-
#
|
96
|
-
# Company.projects
|
97
|
-
#
|
98
|
-
# In this case, you can set the collection_name in belongs_to:
|
99
|
-
#
|
100
|
-
# nested_belongs_to :project, :collection_name => 'admin_projects'
|
101
|
-
#
|
102
|
-
# = polymorphic associations
|
103
|
-
#
|
104
|
-
# In some cases you have a resource that belongs to two different resources
|
105
|
-
# but not at the same time. For example, let's suppose you have File, Message
|
106
|
-
# and Task as resources and they are all commentable.
|
107
|
-
#
|
108
|
-
# Polymorphic associations allows you to create just one controller that will
|
109
|
-
# deal with each case.
|
110
|
-
#
|
111
|
-
# class Comment < InheritedResources::Base
|
112
|
-
# belongs_to :file, :message, :task, :polymorphic => true
|
113
|
-
# end
|
114
|
-
#
|
115
|
-
# Your routes should be something like:
|
116
|
-
#
|
117
|
-
# m.resources :files, :has_many => :comments #=> /files/13/comments
|
118
|
-
# m.resources :tasks, :has_many => :comments #=> /tasks/17/comments
|
119
|
-
# m.resources :messages, :has_many => :comments #=> /messages/11/comments
|
120
|
-
#
|
121
|
-
# When using polymorphic associations, you get some free helpers:
|
122
|
-
#
|
123
|
-
# parent? #=> true
|
124
|
-
# parent_type #=> :task
|
125
|
-
# parent_class #=> Task
|
126
|
-
# parent #=> @task
|
127
|
-
#
|
128
|
-
# This polymorphic controllers thing is a great idea by James Golick and he
|
129
|
-
# built it in resource_controller. Here is just a re-implementation.
|
130
|
-
#
|
131
|
-
# = nested polymorphic associations
|
132
|
-
#
|
133
|
-
# You can have polymorphic associations with nested resources. Let's suppose
|
134
|
-
# that our File, Task and Message resources in the previous example belongs to
|
135
|
-
# a project.
|
136
|
-
#
|
137
|
-
# This way we can have:
|
138
|
-
#
|
139
|
-
# class Comment < InheritedResources::Base
|
140
|
-
# belongs_to :project {
|
141
|
-
# belongs_to :file, :message, :task, :polymorphic => true
|
142
|
-
# }
|
143
|
-
# end
|
144
|
-
#
|
145
|
-
# Or:
|
146
|
-
#
|
147
|
-
# class Comment < InheritedResources::Base
|
148
|
-
# nested_belongs_to :project
|
149
|
-
# nested_belongs_to :file, :message, :task, :polymorphic => true
|
150
|
-
# end
|
151
|
-
#
|
152
|
-
# Choose the syntax that makes more sense to you. :)
|
153
|
-
#
|
154
|
-
# Finally your routes should be something like:
|
155
|
-
#
|
156
|
-
# map.resources :projects do |m|
|
157
|
-
# m.resources :files, :has_many => :comments #=> /projects/1/files/13/comments
|
158
|
-
# m.resources :tasks, :has_many => :comments #=> /projects/1/tasks/17/comments
|
159
|
-
# m.resources :messages, :has_many => :comments #=> /projects/1/messages/11/comments
|
160
|
-
# end
|
161
|
-
#
|
162
|
-
# The helpers work in the same way as above.
|
163
|
-
#
|
164
|
-
# = singleton
|
165
|
-
#
|
166
|
-
# If you have singleton resources, in other words, if your controller resource
|
167
|
-
# associates to another through a has_one association, you can pass the option
|
168
|
-
# :singleton to it. It will deal with all the details and automacally remove
|
169
|
-
# the :index action.
|
170
|
-
#
|
171
|
-
# class ManagersController < InheritedResources::Base
|
172
|
-
# belongs_to :project, :singleton => true # a project has one manager
|
173
|
-
# end
|
174
|
-
#
|
175
|
-
module InheritedResources #:nodoc:
|
176
|
-
module BelongsTo #:nodoc:
|
177
|
-
|
178
|
-
protected
|
179
|
-
def belongs_to(*symbols, &block)
|
180
|
-
options = symbols.extract_options!
|
181
|
-
|
182
|
-
options.symbolize_keys!
|
183
|
-
options.assert_valid_keys(:class_name, :parent_class, :instance_name, :param, :finder, :route_name, :collection_name, :singleton, :polymorphic)
|
184
|
-
|
185
|
-
acts_as_singleton! if singleton = options.delete(:singleton)
|
186
|
-
acts_as_polymorphic! if polymorphic = options.delete(:polymorphic)
|
187
|
-
|
188
|
-
raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty?
|
189
|
-
raise ArgumentError, 'You cannot define multiple associations with the options: #{options.keys.inspect}.' unless symbols.size == 1 || options.empty?
|
190
|
-
|
191
|
-
# Add BelongsToHelpers if we haven't yet.
|
192
|
-
include BelongsToHelpers if self.parents_symbols.empty?
|
193
|
-
|
194
|
-
# Set configuration default values
|
195
|
-
symbols.each do |symbol|
|
196
|
-
symbol = symbol.to_sym
|
197
|
-
|
198
|
-
if polymorphic
|
199
|
-
self.parents_symbols << :polymorphic unless self.parents_symbols.include? :polymorphic
|
200
|
-
self.polymorphic_symbols << symbol
|
201
|
-
else
|
202
|
-
self.parents_symbols << symbol
|
203
|
-
end
|
204
|
-
|
205
|
-
config = self.resources_configuration[symbol] = {}
|
206
|
-
config[:parent_class] = options.delete(:parent_class)
|
207
|
-
config[:parent_class] ||= (options.delete(:class_name) || symbol).to_s.classify.constantize rescue nil
|
208
|
-
config[:collection_name] = (options.delete(:collection_name) || symbol.to_s.pluralize).to_sym
|
209
|
-
config[:instance_name] = (options.delete(:instance_name) || symbol).to_sym
|
210
|
-
config[:param] = (options.delete(:param) || "#{symbol}_id").to_sym
|
211
|
-
config[:finder] = (options.delete(:finder) || :find).to_sym
|
212
|
-
config[:route_name] = (options.delete(:route_name) || symbol).to_s
|
213
|
-
config[:polymorphic] = polymorphic
|
214
|
-
end
|
215
|
-
|
216
|
-
# Regenerate url helpers unless block is given
|
217
|
-
if block_given?
|
218
|
-
class_eval(&block)
|
219
|
-
else
|
220
|
-
InheritedResources::UrlHelpers.create_resources_url_helpers!(self)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
alias :nested_belongs_to :belongs_to
|
224
|
-
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|