josevalim-inherited_resources 0.1
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 +4 -0
- data/MIT-LICENSE +21 -0
- data/README +362 -0
- data/Rakefile +19 -0
- data/init.rb +1 -0
- data/lib/inherited_resources.rb +4 -0
- data/lib/inherited_resources/base.rb +272 -0
- data/lib/inherited_resources/base_helpers.rb +199 -0
- data/lib/inherited_resources/belongs_to.rb +227 -0
- data/lib/inherited_resources/belongs_to_helpers.rb +89 -0
- data/lib/inherited_resources/class_methods.rb +155 -0
- data/lib/inherited_resources/polymorphic_helpers.rb +19 -0
- data/lib/inherited_resources/respond_to.rb +324 -0
- data/lib/inherited_resources/singleton_helpers.rb +53 -0
- data/lib/inherited_resources/url_helpers.rb +147 -0
- data/test/aliases_test.rb +71 -0
- data/test/base_helpers_test.rb +130 -0
- data/test/base_test.rb +219 -0
- data/test/belongs_to_base_test.rb +268 -0
- data/test/belongs_to_test.rb +109 -0
- data/test/class_methods_test.rb +73 -0
- data/test/fixtures/en.yml +9 -0
- data/test/nested_belongs_to_test.rb +138 -0
- data/test/polymorphic_base_test.rb +282 -0
- data/test/respond_to_test.rb +282 -0
- data/test/singleton_base_test.rb +226 -0
- data/test/test_helper.rb +37 -0
- data/test/url_helpers_test.rb +284 -0
- data/test/views/cities/edit.html.erb +1 -0
- data/test/views/cities/index.html.erb +1 -0
- data/test/views/cities/new.html.erb +1 -0
- data/test/views/cities/show.html.erb +1 -0
- data/test/views/comments/edit.html.erb +1 -0
- data/test/views/comments/index.html.erb +1 -0
- data/test/views/comments/new.html.erb +1 -0
- data/test/views/comments/show.html.erb +1 -0
- data/test/views/employees/edit.html.erb +1 -0
- data/test/views/employees/index.html.erb +1 -0
- data/test/views/employees/new.html.erb +1 -0
- data/test/views/employees/show.html.erb +1 -0
- data/test/views/managers/edit.html.erb +1 -0
- data/test/views/managers/new.html.erb +1 -0
- data/test/views/managers/show.html.erb +1 -0
- data/test/views/pets/edit.html.erb +1 -0
- data/test/views/professors/edit.html.erb +1 -0
- data/test/views/professors/index.html.erb +1 -0
- data/test/views/professors/new.html.erb +1 -0
- data/test/views/professors/show.html.erb +1 -0
- data/test/views/projects/index.html.erb +1 -0
- data/test/views/projects/respond_to_with_resource.html.erb +1 -0
- data/test/views/students/edit.html.erb +1 -0
- data/test/views/students/new.html.erb +1 -0
- data/test/views/users/edit.html.erb +1 -0
- data/test/views/users/index.html.erb +1 -0
- data/test/views/users/new.html.erb +1 -0
- data/test/views/users/show.html.erb +1 -0
- metadata +108 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
module InheritedResources #:nodoc:
|
2
|
+
module BaseHelpers #:nodoc:
|
3
|
+
|
4
|
+
# Protected helpers. You might want to overwrite some of them.
|
5
|
+
protected
|
6
|
+
# This is how the collection is loaded.
|
7
|
+
#
|
8
|
+
# You might want to overwrite this method if you want to add pagination
|
9
|
+
# for example. When you do that, don't forget to cache the result in an
|
10
|
+
# instance_variable:
|
11
|
+
#
|
12
|
+
# def collection
|
13
|
+
# @projects ||= end_of_association_chain.paginate(params[:page]).all
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
def collection
|
17
|
+
get_collection_ivar || set_collection_ivar(end_of_association_chain.find(:all))
|
18
|
+
end
|
19
|
+
|
20
|
+
# This is how the resource is loaded.
|
21
|
+
#
|
22
|
+
# You might want to overwrite this method when you are using permalink.
|
23
|
+
# When you do that, don't forget to cache the result in an
|
24
|
+
# instance_variable:
|
25
|
+
#
|
26
|
+
# def resource
|
27
|
+
# @project ||= end_of_association_chain.find_by_permalink!(params[:id])
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# You also might want to add the exclamation mark at the end of the method
|
31
|
+
# because it will raise a 404 if nothing can be found. Otherwise it will
|
32
|
+
# probably render a 500 error message.
|
33
|
+
#
|
34
|
+
def resource
|
35
|
+
get_resource_ivar || set_resource_ivar(end_of_association_chain.find(params[:id]))
|
36
|
+
end
|
37
|
+
|
38
|
+
# This method is responsable for building the object on :new and :create
|
39
|
+
# methods. You probably won't need to change it. Again, if you overwrite
|
40
|
+
# don't forget to cache the result in an instance_variable.
|
41
|
+
#
|
42
|
+
def build_resource(attributes = {})
|
43
|
+
get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_build, attributes))
|
44
|
+
end
|
45
|
+
|
46
|
+
# This class allows you to set a instance variable to begin your
|
47
|
+
# association chain. For example, usually your projects belongs to users
|
48
|
+
# and that means that they belong to the current logged in user. So you
|
49
|
+
# could do this:
|
50
|
+
#
|
51
|
+
# def begin_of_association_chain
|
52
|
+
# @current_user
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# So every time we instantiate a project, we will do:
|
56
|
+
#
|
57
|
+
# @current_user.projects.build(params[:project])
|
58
|
+
# @current_user.projects.find(params[:id])
|
59
|
+
#
|
60
|
+
# The variable set in begin_of_association_chain is not sent when building
|
61
|
+
# urls, so this is never going to happen:
|
62
|
+
#
|
63
|
+
# project_url(@current_user, @project)
|
64
|
+
#
|
65
|
+
# If the user actually scopes the url, you should user belongs_to method
|
66
|
+
# and declare that projects belong to user.
|
67
|
+
#
|
68
|
+
def begin_of_association_chain
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
# Private helpers, you probably don't have to worry with them.
|
73
|
+
private
|
74
|
+
|
75
|
+
# Fast accessor to resource_collection_name
|
76
|
+
#
|
77
|
+
def resource_collection_name
|
78
|
+
resources_configuration[:self][:collection_name]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Fast accessor to resource_instance_name
|
82
|
+
#
|
83
|
+
def resource_instance_name
|
84
|
+
resources_configuration[:self][:instance_name]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns if the object has a parent. This means, if it has an object
|
88
|
+
# set at begin_of_association_chain is not nil.
|
89
|
+
#
|
90
|
+
def parent?
|
91
|
+
!begin_of_association_chain.nil?
|
92
|
+
end
|
93
|
+
|
94
|
+
# This methods gets your begin_of_association_chain and returns the
|
95
|
+
# scoped association.
|
96
|
+
#
|
97
|
+
def end_of_association_chain
|
98
|
+
if parent?
|
99
|
+
begin_of_association_chain.send(resource_collection_name)
|
100
|
+
else
|
101
|
+
resource_class
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns the appropriated method to build the resource.
|
106
|
+
#
|
107
|
+
def method_for_build
|
108
|
+
parent? ? :build : :new
|
109
|
+
end
|
110
|
+
|
111
|
+
# Get resource ivar based on the current resource controller.
|
112
|
+
#
|
113
|
+
def get_resource_ivar
|
114
|
+
instance_variable_get("@#{resource_instance_name}")
|
115
|
+
end
|
116
|
+
|
117
|
+
# Set resource ivar based on the current resource controller.
|
118
|
+
#
|
119
|
+
def set_resource_ivar(resource)
|
120
|
+
instance_variable_set("@#{resource_instance_name}", resource)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get collection ivar based on the current resource controller.
|
124
|
+
#
|
125
|
+
def get_collection_ivar
|
126
|
+
instance_variable_get("@#{resource_collection_name}")
|
127
|
+
end
|
128
|
+
|
129
|
+
# Set collection ivar based on the current resource controller.
|
130
|
+
#
|
131
|
+
def set_collection_ivar(collection)
|
132
|
+
instance_variable_set("@#{resource_collection_name}", collection)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Helper to set flash messages. It's powered by I18n API.
|
136
|
+
# It checks for messages in the following order:
|
137
|
+
#
|
138
|
+
# flash.controller_name.action_name.status
|
139
|
+
# flash.actions.action_name.status
|
140
|
+
#
|
141
|
+
# If none is available, a default message is set. So, if you have
|
142
|
+
# a CarsController, create action, it will check for:
|
143
|
+
#
|
144
|
+
# flash.cars.create.status
|
145
|
+
# flash.actions.create.status
|
146
|
+
#
|
147
|
+
# The statuses can be :notice (when the object can be created, updated
|
148
|
+
# or destroyed with success) or :error (when the objecy cannot be created
|
149
|
+
# or updated).
|
150
|
+
#
|
151
|
+
# Those messages are interpolated by using the resource class human name.
|
152
|
+
# This means you can set:
|
153
|
+
#
|
154
|
+
# flash:
|
155
|
+
# actions:
|
156
|
+
# create:
|
157
|
+
# notice: "Hooray! {{resource}} was successfully created!"
|
158
|
+
#
|
159
|
+
# But sometimes, flash messages are not that simple. Going back
|
160
|
+
# to cars example, you might want to say the brand of the car when it's
|
161
|
+
# updated. Well, that's easy also:
|
162
|
+
#
|
163
|
+
# flash:
|
164
|
+
# cars:
|
165
|
+
# update:
|
166
|
+
# notice: "Hooray! You just tuned your {{car_brand}}!"
|
167
|
+
#
|
168
|
+
# Since :car_name is not available for interpolation by default, you have
|
169
|
+
# to overwrite interpolation_options.
|
170
|
+
#
|
171
|
+
# def interpolation_options
|
172
|
+
# { :car_brand => @car.brand }
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# Then you will finally have:
|
176
|
+
#
|
177
|
+
# 'Hooray! You just tuned your Aston Martin!'
|
178
|
+
#
|
179
|
+
def set_flash_message!(status, default_message = '')
|
180
|
+
options = {
|
181
|
+
:default => [ :"flash.actions.#{action_name}.#{status}", default_message ],
|
182
|
+
:resource => resource_class.human_name
|
183
|
+
}.merge(interpolation_options)
|
184
|
+
|
185
|
+
message = I18n.t "flash.#{controller_name}.#{action_name}.#{status}", options
|
186
|
+
|
187
|
+
flash[status] = message unless message.blank?
|
188
|
+
end
|
189
|
+
|
190
|
+
# Overwrite this method to provide other interpolation options when
|
191
|
+
# the flash message is going to be set. Check set_flash_message! for
|
192
|
+
# more information.
|
193
|
+
#
|
194
|
+
def interpolation_options
|
195
|
+
{ }
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,227 @@
|
|
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_instance #=> @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
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module InheritedResources #:nodoc:
|
2
|
+
module BelongsToHelpers #:nodoc:
|
3
|
+
|
4
|
+
# Private helpers, you probably don't have to worry with them.
|
5
|
+
private
|
6
|
+
|
7
|
+
# Overwrites the parent? method defined in base_helpers.rb.
|
8
|
+
# This one always returns true since it's added when associations
|
9
|
+
# are defined.
|
10
|
+
#
|
11
|
+
def parent?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
# Evaluate the parent given. This is used to nest parents in the
|
16
|
+
# association chain.
|
17
|
+
#
|
18
|
+
def evaluate_parent(parent_config, chain = nil)
|
19
|
+
scoped_parent = if chain
|
20
|
+
chain.send(parent_config[:collection_name])
|
21
|
+
else
|
22
|
+
parent_config[:parent_class]
|
23
|
+
end
|
24
|
+
|
25
|
+
scoped_parent = scoped_parent.send(parent_config[:finder], params[parent_config[:param]])
|
26
|
+
|
27
|
+
instance_variable_set("@#{parent_config[:instance_name]}", scoped_parent)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Overwrites the end_of_association_chain method.
|
31
|
+
#
|
32
|
+
# This methods gets your begin_of_association_chain, join it with your
|
33
|
+
# parents chain and returns the scoped association.
|
34
|
+
#
|
35
|
+
def end_of_association_chain
|
36
|
+
return resource_class unless parent?
|
37
|
+
|
38
|
+
chain = symbols_for_chain.inject(begin_of_association_chain) do |chain, symbol|
|
39
|
+
evaluate_parent(resources_configuration[symbol], chain)
|
40
|
+
end
|
41
|
+
|
42
|
+
chain = chain.send(method_for_association_chain) if method_for_association_chain
|
43
|
+
|
44
|
+
return chain
|
45
|
+
end
|
46
|
+
|
47
|
+
# If current controller is singleton, returns instance name to
|
48
|
+
# end_of_association_chain. This means that we will have the following
|
49
|
+
# chain:
|
50
|
+
#
|
51
|
+
# Project.find(params[:project_id]).manager
|
52
|
+
#
|
53
|
+
# Instead of:
|
54
|
+
#
|
55
|
+
# Project.find(params[:project_id]).managers
|
56
|
+
#
|
57
|
+
def method_for_association_chain
|
58
|
+
singleton ? nil : resource_collection_name
|
59
|
+
end
|
60
|
+
|
61
|
+
# Maps parents_symbols to build association chain.
|
62
|
+
#
|
63
|
+
# If the parents_symbols find :polymorphic, it goes through the
|
64
|
+
# params keys to see which polymorphic parent matches the given params.
|
65
|
+
#
|
66
|
+
def symbols_for_chain
|
67
|
+
parents_symbols.map do |symbol|
|
68
|
+
if symbol == :polymorphic
|
69
|
+
params_keys = params.keys
|
70
|
+
|
71
|
+
key = polymorphic_symbols.find do |poly|
|
72
|
+
params_keys.include? resources_configuration[poly][:param].to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
raise ScriptError, "Could not find param for polymorphic association.
|
76
|
+
The request params keys are #{params.keys.inspect}
|
77
|
+
and the polymorphic associations are
|
78
|
+
#{polymorphic_symbols.inspect}." if key.nil?
|
79
|
+
|
80
|
+
instance_variable_set('@parent_type', key.to_sym)
|
81
|
+
else
|
82
|
+
symbol
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|