aeonscope-rest 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +25 -0
- data/README.rdoc +42 -30
- data/Rakefile +2 -2
- data/VERSION.yml +1 -1
- data/lib/class_methods.rb +17 -17
- data/lib/instance_methods.rb +261 -0
- data/lib/resource_helper.rb +133 -50
- data/lib/rest.rb +2 -2
- data/rails_generators/{ujs_setup → rest_setup}/USAGE +2 -2
- data/rails_generators/rest_setup/rest_setup_generator.rb +28 -0
- data/rails_generators/{ujs_setup → rest_setup}/templates/README +1 -1
- data/rails_generators/{ujs_setup → rest_setup}/templates/app/controllers/javascripts_controller.rb +0 -0
- data/rails_generators/{ujs_setup → rest_setup}/templates/app/views/javascripts/ujs.js.erb +3 -3
- data/rails_generators/rest_setup/templates/config/initializers/pagination.rb +10 -0
- data/rails_generators/rest_setup/templates/public/javascripts/jquery.rest.js +325 -0
- data/rails_generators/rest_setup/templates/public/themes/default/images/icons/rest/destroy.png +0 -0
- data/rails_generators/rest_setup/templates/public/themes/default/images/icons/rest/edit.png +0 -0
- data/rails_generators/rest_setup/templates/public/themes/default/images/icons/rest/new.png +0 -0
- data/rails_generators/rest_setup/templates/public/themes/default/images/icons/rest/show.png +0 -0
- metadata +17 -12
- data/lib/actions.rb +0 -230
- data/rails_generators/ujs_setup/templates/public/javascripts/rest.js +0 -119
- data/rails_generators/ujs_setup/ujs_setup_generator.rb +0 -18
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
= v1.1.0
|
2
|
+
|
3
|
+
* Clarified the readme documentation.
|
4
|
+
* Updated the JavaScript code so that events are bound for current and future instances instead of just once.
|
5
|
+
* Fixed a JavaScript bug where deleting nested inputs on a new form would cause an exception.
|
6
|
+
* Updated the JavaScript code so that new records are initially hidden.
|
7
|
+
* Updated the JavaScript code so the last record of a form is not deleted. Contents will be cleared and hidden (if last element).
|
8
|
+
* Applied fade in/out effects when adding/destroying input forms.
|
9
|
+
* Removed the hiding of the delete link via the various resource helpers.
|
10
|
+
* Modified the JavaScript incrementNumber(string, position) function for better handling of complex nested Rails model forms.
|
11
|
+
* Renamed all forms of the "new" action UJS classes to a single "new" class. Use the data-type attribute to distinguish type.
|
12
|
+
* Applied "group" and "record" classes to distinguish between a group of records and a single record. Very handy for creating and/or destroying form elements.
|
13
|
+
* Renamed the various resource helpers to be aware of input elements (this affects the destroy helpers mostly).
|
14
|
+
* Added default option support for the Will Paginate gem requirement (use config/initializers/pagination.rb to change settings).
|
15
|
+
* Renamed all "show_" helpers to "render_" helpers.
|
16
|
+
* Added a render_show_link helper.
|
17
|
+
* Added a render_new_link helper.
|
18
|
+
* Added a render_edit_link helper.
|
19
|
+
* Added icons for show, new, edit, and destroy actions. All corresponding helpers default to these icons.
|
20
|
+
* Changed the rendering of partials to templates for all REST actions.
|
21
|
+
* Added the ability to supply an index template if you wish to override the default index action behavior.
|
22
|
+
* Added basic AJAX handling for the destroy action so that a response can be sent back to the JavaScript caller.
|
23
|
+
* Moved all JavaScript REST functionality into a proper jQuery plugin.
|
24
|
+
* Renamed the "ujs_setup" generator to "rest_setup".
|
25
|
+
|
1
26
|
= v1.0.0
|
2
27
|
|
3
28
|
* Initial version.
|
data/README.rdoc
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
= Overview
|
2
2
|
|
3
|
-
Enables default REST functionality, more than what you get with Rails out-of-the-box,
|
3
|
+
Enables default REST functionality, more than what you get with Rails out-of-the-box, to keep your code DRY. This means you can write code like this:
|
4
4
|
|
5
5
|
class Posts < ApplicationController
|
6
6
|
include Rest
|
7
7
|
end
|
8
8
|
|
9
|
-
Which would automatically
|
9
|
+
Which would automatically add the following REST actions to your controller:
|
10
10
|
|
11
11
|
* index
|
12
12
|
* show
|
@@ -29,9 +29,9 @@ See the CHANGELOG file for more info.
|
|
29
29
|
|
30
30
|
= Requirements
|
31
31
|
|
32
|
-
1. {
|
33
|
-
2.
|
34
|
-
3.
|
32
|
+
1. Knowledge of {Representational State Transfer (REST)}[http://en.wikipedia.com/wiki/REST].
|
33
|
+
2. {Ruby on Rails}[http://rubyonrails.org] (automatically installed for you if you don't have 2.3.x or higher).
|
34
|
+
3. mislav-will_paginate[http://github.com/mislav/will_paginate/tree/master] gem (automatically installed for you).
|
35
35
|
|
36
36
|
= Installation
|
37
37
|
|
@@ -42,11 +42,11 @@ Type the following from the command line to install:
|
|
42
42
|
|
43
43
|
Update your environment.rb file to include the new gem:
|
44
44
|
|
45
|
-
* config.gem "rest"
|
45
|
+
* config.gem "aeonscope-rest", :lib => "rest", :source => "http://gems.github.com"
|
46
46
|
|
47
|
-
|
47
|
+
Then run the following generator to complete setup (TIP: suffix the command line with -h option for usage):
|
48
48
|
|
49
|
-
* script/generate
|
49
|
+
* script/generate rest_setup
|
50
50
|
|
51
51
|
= Usage
|
52
52
|
|
@@ -60,7 +60,11 @@ Example:
|
|
60
60
|
include Rest
|
61
61
|
end
|
62
62
|
|
63
|
-
This will automatically create the seven REST actions (index, show, new, create, edit, update, and destroy) for your controller. The model (i.e. Post) and model instance (i.e. @posts or @post depending on the action) are automatically determined from the controller name
|
63
|
+
This will automatically create the seven REST actions (index, show, new, create, edit, update, and destroy) for your controller. The model (i.e. Post) and model instance (i.e. @posts or @post depending on the action) are automatically determined from the controller name. Just make sure your routes are updated to reflect the new resource. For example:
|
64
|
+
|
65
|
+
map.resources :posts
|
66
|
+
|
67
|
+
This means you can immediately write the following code in your views:
|
64
68
|
|
65
69
|
<b>index.html.erb</b>
|
66
70
|
|
@@ -91,7 +95,7 @@ This will automatically create the seven REST actions (index, show, new, create,
|
|
91
95
|
|
92
96
|
<p><%= link_to "Back", :back %></p>
|
93
97
|
|
94
|
-
<b>
|
98
|
+
<b>new_or_edit.html.erb</b>
|
95
99
|
|
96
100
|
<% form_for @post do |form| %>
|
97
101
|
<%= form.error_messages :header_data => :strong, :header_message => "Error" %>
|
@@ -106,14 +110,10 @@ This will automatically create the seven REST actions (index, show, new, create,
|
|
106
110
|
<%= form.text_area :content %>
|
107
111
|
</div>
|
108
112
|
|
109
|
-
<div><%=
|
113
|
+
<div><%= submit_tag "Save", :class => "form-button" %> or <%= link_to "Cancel", posts_path %></div>
|
110
114
|
<% end %>
|
111
115
|
|
112
|
-
|
113
|
-
|
114
|
-
Use the same code as shown in the new.html.erb view above. ;-) The Rails form_for helper will automatically determine what action to take as shown in the following code:
|
115
|
-
|
116
|
-
<% form_for @post do |form| %>
|
116
|
+
Notice how the form_for[http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for] helper method automatically determines what controller action to use based off the model object (i.e. @post). This allows you to use the same form for new and edit actions by creating one template called: new_or_edit.html.erb. Nice, eh?
|
117
117
|
|
118
118
|
To customize the RESTful behavior of your controller, use any combination of these three macros:
|
119
119
|
|
@@ -133,7 +133,7 @@ Example:
|
|
133
133
|
Here is the breakdown, line-by-line, of the example shown above:
|
134
134
|
|
135
135
|
1. Enables restful behavior.
|
136
|
-
2. Identifies the controller as a
|
136
|
+
2. Identifies the comments controller as a child of the posts controller (i.e. nested resource).
|
137
137
|
3. Instead of using the default label "Comments", a customized label of "My Wicked Comments" is used instead.
|
138
138
|
4. The "show" and "destroy" actions are disabled which means only the following actions will work: index, new, edit, create, and update.
|
139
139
|
|
@@ -142,28 +142,40 @@ Using the post and comment controller relationship as defined above, we can brea
|
|
142
142
|
* *parent_key* = N/A
|
143
143
|
* *parent_value* = N/A
|
144
144
|
* *parent_resource_method* = N/A
|
145
|
-
* *
|
145
|
+
* *controller_class* = PostsController
|
146
|
+
* *controller_name* = "posts"
|
146
147
|
* *label* = "Posts"
|
147
|
-
* *
|
148
|
-
* *
|
149
|
-
* *
|
148
|
+
* *model_class* = Post
|
149
|
+
* *model_name* = post
|
150
|
+
* *model_object* = @post #<Post id: 1, label: "Test", content: "Test", created_at: "2008-10-31 23:59:28", updated_at: "2008-10-31 23:59:28">
|
150
151
|
* *namespaces* = []
|
151
|
-
* *
|
152
|
-
* *
|
152
|
+
* *index_template* = "/posts/index"
|
153
|
+
* *show_template* = "/posts/show"
|
154
|
+
* *new_or_edit_template* = "/posts/new_or_edit"
|
153
155
|
|
154
156
|
The comment (child) resource would have the following values:
|
155
|
-
|
157
|
+
|
156
158
|
* *parent_key* = post_id
|
157
159
|
* *parent_value* = 1
|
158
160
|
* *parent_resource_method* = N/A
|
159
|
-
* *
|
161
|
+
* *controller_class* = CommentsController
|
162
|
+
* *controller_name* = "comments"
|
160
163
|
* *label* = "My Wicked Comments"
|
161
|
-
* *
|
162
|
-
* *
|
163
|
-
* *
|
164
|
+
* *model_class* = Comment
|
165
|
+
* *model_name* = comment
|
166
|
+
* *model_object* = @comment #<Comment id: 1, post_id: 1, label: "Test", content: "Test", created_at: "2008-10-31 23:59:28", updated_at: "2008-10-31 23:59:28">
|
164
167
|
* *namespaces* = []
|
165
|
-
* *
|
166
|
-
* *
|
168
|
+
* *index_template* = "/comments/index"
|
169
|
+
* *show_template* = "/comments/show"
|
170
|
+
* *new_or_edit_template* = "/comments/new_or_edit"
|
171
|
+
|
172
|
+
Resources
|
173
|
+
|
174
|
+
To learn more about REST in Rails, check out the following:
|
175
|
+
|
176
|
+
* {RESTful Rails}[http://www.b-simple.de/documents] - A PDF work downloading and reading that inspired me to write this gem.
|
177
|
+
* {Rails Routing}[http://guides.rails.info/routing.html] - The definitive guide to RESTful routing in Rails.
|
178
|
+
* {Taking Things Too Far}[http://www.therailsway.com/2009/6/22/taking-things-too-far-rest] - A good read on knowing when you have gone too far with REST API.
|
167
179
|
|
168
180
|
= Contact/Feedback/Issues
|
169
181
|
|
data/Rakefile
CHANGED
@@ -5,14 +5,14 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "rest"
|
8
|
-
gem.summary = "Enables default REST functionality,
|
8
|
+
gem.summary = "Enables default REST functionality, UJS support (jQuery), and keeps your code DRY."
|
9
9
|
gem.description = "Ruby on Rails supports RESTful routing out-of-the-box. However, as you move along, you will often find yourself repeating the code for the seven REST actions: index, show, new, create, edit, update, destroy. This gem allows you to get all of the code for free by simply typing 'include Rest' at top of your controller code. That's it! Even better, you can have nested resources as well by adding a 'belongs_to' statement to your controllers much like you would for ActiveRecord models. This is just the tip of the iceburg so make sure to read the RDoc for more info."
|
10
10
|
gem.authors = ["Brooke Kuhlmann"]
|
11
11
|
gem.email = "aeonscope@gmail.com"
|
12
12
|
gem.homepage = "http://github.com/aeonscope/rest"
|
13
13
|
gem.required_ruby_version = ">= 1.8.6"
|
14
14
|
gem.add_dependency "rails", ">= 2.3.2"
|
15
|
-
gem.add_dependency "mislav-will_paginate", ">= 2.3.
|
15
|
+
gem.add_dependency "mislav-will_paginate", ">= 2.3.10"
|
16
16
|
gem.rdoc_options << "CHANGELOG.rdoc"
|
17
17
|
gem.files = FileList["[A-Z]*", "{bin,lib,generators,rails_generators,test,spec}/**/*"]
|
18
18
|
end
|
data/VERSION.yml
CHANGED
data/lib/class_methods.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
1
|
module Rest
|
2
2
|
module ClassMethods
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# * *parent* - The parent symbol (including namespaces delimited by underscores). Be sure to reflect singular or plural forms on the name. Example: Public::PostsController, Result: :public_posts
|
3
|
+
# Describes the parent/child relationship of a resource. The behavior is similar to the belongs_to macro in ActiveRecord.
|
4
|
+
# * *parent* - The parent symbol (including namespaces delimited by underscores). Example: Public::PostsController, Result: :public_posts
|
6
5
|
def belongs_to parent
|
7
6
|
@parent_resource = parent.to_s
|
8
7
|
class_eval "class << self; attr_accessor :parent_resource end"
|
9
8
|
end
|
10
9
|
|
11
|
-
# Allows one to specify the various options for a resource.
|
12
|
-
# * *parent_key* - The ID key of the parent resource (for nested resources only). Defaults to: <belongs_to name>_id
|
13
|
-
# * *parent_value* - The ID value of the parent resource (for nested resources only). Defaults to the record id.
|
14
|
-
# * *parent_resource_method* - The instance method to call for acquiring child resource(s) of the parent (for nested resources only). Example: A post with many comments would be post.comments. Defaults to child resource name.
|
15
|
-
# * *
|
16
|
-
# * *
|
17
|
-
# * *
|
18
|
-
# * *
|
19
|
-
# * *
|
20
|
-
# * *
|
21
|
-
# * *
|
22
|
-
# * *
|
10
|
+
# Allows one to specify the various options for a resource.
|
11
|
+
# * *parent_key* - Optional. The ID key of the parent resource (for nested resources only). Defaults to: <belongs_to name>_id
|
12
|
+
# * *parent_value* - Optional. The ID value of the parent resource (for nested resources only). Defaults to the record id.
|
13
|
+
# * *parent_resource_method* - Optional. The instance method to call for acquiring child resource(s) of the parent (for nested resources only). Example: A post with many comments would be post.comments. Defaults to child resource name.
|
14
|
+
# * *controller_class* - Optional. The controller class (for nested resources only). Defaults to the current class. You should never need to use this.
|
15
|
+
# * *controller_name* - Optional. The controller name. Defaults to the controller class name minus the "Controller" suffix (same behavior as used in routing). Example: PostsController => posts
|
16
|
+
# * *label* - Optional. The resource label. Defaults to the controller name with capitalization. Example: posts => Posts.
|
17
|
+
# * *model_class* - Optional. The model class. Defaults to the same name as the controller (minus namespace, suffix, and pluralization of course). Example: PostsController => Post
|
18
|
+
# * *model_name* - Optional. The model name. Defaults to the singularized version of the :controller_name. Example: posts (controller_name) => post (model_name).
|
19
|
+
# * *model_object* - Optional. The model object. The name defaults to the model_name. Example: post (model_name) => @post (model object). You should never need to use this.
|
20
|
+
# * *namespaces* - Optional. The namespaces (if any) for routing. Defaults to whatever namespace your controller is using.
|
21
|
+
# * *index_template* - Optional. The index template. Defaults to "/<namspace(s)>/<controller name>/index".
|
22
|
+
# * *show_template* - Optional. The show template. Defaults to "/<namspace(s)>/<controller name>/show".
|
23
|
+
# * *new_or_edit_template* - Optional. The new or edit template. Defaults to "/<namspace(s)>/<controller name>/new_or_edit".
|
23
24
|
def resource_options options = {}
|
24
25
|
@resource_options = options
|
25
26
|
class_eval "class << self; attr_reader :resource_options end"
|
26
27
|
end
|
27
28
|
|
28
|
-
# Allows one to disable any number of default actions.
|
29
|
+
# Allows one to disable any number of default actions.
|
29
30
|
# * *actions* - A variable list of REST action symbols you wish to disable. You may use any of the following: index, show, new, create, edit, update, and/or destroy.
|
30
31
|
def disabled_actions *actions
|
31
32
|
actions.uniq.each {|action| undef_method action}
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
35
|
-
|
@@ -0,0 +1,261 @@
|
|
1
|
+
module Rest
|
2
|
+
module InstanceMethods
|
3
|
+
# Default index action.
|
4
|
+
# See config/initializers/pagination.rb to change default pagination settings.
|
5
|
+
def index
|
6
|
+
build_resources
|
7
|
+
if @resources.size > 1
|
8
|
+
# Model objects for a nested resource (act on the second-to-last parent).
|
9
|
+
parent = @resources[@resources.size - 2][:model_object]
|
10
|
+
mname = parent.class.name.underscore.pluralize
|
11
|
+
model_objects = parent.instance_eval("#{@resources.last[:parent_resource_method] || @resources.last[:controller_name]}").paginate PAGINATION_PARAM_NAME => params[PAGINATION_PARAM_NAME], :per_page => PAGINATION_PAGE_COUNT
|
12
|
+
else
|
13
|
+
# Model objects for a single resource.
|
14
|
+
if model_name
|
15
|
+
mname = model_name.pluralize
|
16
|
+
model_objects = model_class.all.paginate(PAGINATION_PARAM_NAME => params[PAGINATION_PARAM_NAME], :per_page => PAGINATION_PAGE_COUNT)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
instance_variable_set "@#{mname}", model_objects if mname
|
20
|
+
render_action_template @resources.last[:index_template]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Default show action.
|
24
|
+
def show
|
25
|
+
build_resources
|
26
|
+
render_action_template @resources.last[:show_template]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Default new action.
|
30
|
+
def new
|
31
|
+
build_resources
|
32
|
+
render_new_or_edit_template
|
33
|
+
end
|
34
|
+
|
35
|
+
# Default edit action.
|
36
|
+
def edit
|
37
|
+
build_resources
|
38
|
+
render_new_or_edit_template
|
39
|
+
end
|
40
|
+
|
41
|
+
# Default create action.
|
42
|
+
def create
|
43
|
+
build_resources
|
44
|
+
if model_object.update_attributes params[model_symbol]
|
45
|
+
redirect_to build_resource_url(@resources)
|
46
|
+
else
|
47
|
+
render_new_or_edit_template
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Default update action.
|
52
|
+
def update
|
53
|
+
build_resources
|
54
|
+
if model_object.update_attributes params[model_symbol]
|
55
|
+
redirect_to build_resource_url(@resources)
|
56
|
+
else
|
57
|
+
render_new_or_edit_template
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Default destroy action.
|
62
|
+
def destroy
|
63
|
+
build_resources
|
64
|
+
model_object.destroy
|
65
|
+
@resources.last.delete :model_object
|
66
|
+
respond_to do |format|
|
67
|
+
format.html {redirect_to build_resource_url(@resources)}
|
68
|
+
format.js {render :text => "ok"}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
# Renders an action template.
|
75
|
+
def render_action_template template
|
76
|
+
unless template.blank?
|
77
|
+
symbol = model_symbol
|
78
|
+
object = model_object
|
79
|
+
if symbol && object
|
80
|
+
render :template => template, :locals => {symbol => object, :resources => @resources}
|
81
|
+
else
|
82
|
+
render :template => template, :locals => {:resources => @resources}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Rendering a new/edit template.
|
88
|
+
def render_new_or_edit_template
|
89
|
+
render_action_template @resources.last[:new_or_edit_template]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Builds the RESTful parent URL based on an array of resources.
|
93
|
+
def build_parent_url resources = []
|
94
|
+
namespaces = resources.last[:namespaces]
|
95
|
+
url = namespaces && !namespaces.empty? ? '/' + resources.last[:namespaces].join('/') : nil
|
96
|
+
if resources.size > 1
|
97
|
+
resources.slice(0...resources.size - 1).each do |resource|
|
98
|
+
url = [url, resource[:controller_name], resource[:parent_id]] * '/'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
url
|
102
|
+
end
|
103
|
+
|
104
|
+
# Builds RESTful URLs based on an array of resources with the option to override the default action.
|
105
|
+
# This is also defined as a helper method (see base.rb).
|
106
|
+
def build_resource_url resources = [], action = :index
|
107
|
+
controller_name = resources.last[:controller_name]
|
108
|
+
id = resources.last[:model_object].id if resources.last[:model_object]
|
109
|
+
parent_url = build_parent_url(resources)
|
110
|
+
url = parent_url ? [parent_url, controller_name].join('/') : '/' + controller_name
|
111
|
+
case action
|
112
|
+
when :show then url = [url, id].compact * '/'
|
113
|
+
when :new then url = [url, "new"].compact * '/'
|
114
|
+
when :edit then url = [url, id, "edit"].compact * '/'
|
115
|
+
when :update then url = [url, id].compact.join('/') if controller_name == controller_name.pluralize
|
116
|
+
when :destroy then url = [url, id].compact.join('/') if controller_name == controller_name.pluralize
|
117
|
+
end
|
118
|
+
logger.debug "Resource URL: #{url}"
|
119
|
+
url
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# Answers the current page from the session (if any).
|
125
|
+
def current_page
|
126
|
+
update_page
|
127
|
+
session[controller_symbol("page")] || 1
|
128
|
+
end
|
129
|
+
|
130
|
+
# Updates the current page for the session.
|
131
|
+
def update_page
|
132
|
+
key = controller_symbol("page")
|
133
|
+
case params[:action]
|
134
|
+
when "index" then session[key] = params[:page] if params[:page] && session[key] != params[:page]
|
135
|
+
when "show" then
|
136
|
+
ids = model_class.all.map {|model| model.id}
|
137
|
+
session[key] = (ids.index(params[:id].to_i) + 1) / PAGINATION_PAGE_COUNT
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Answers the class of the current model.
|
142
|
+
def model_class
|
143
|
+
@resources.last[:model_class]
|
144
|
+
end
|
145
|
+
|
146
|
+
# Answers the name of the current model.
|
147
|
+
def model_name
|
148
|
+
@resources.last[:model_name]
|
149
|
+
end
|
150
|
+
|
151
|
+
# Answers the symbol of the current model.
|
152
|
+
# NOTE: The symbol is always derived from the model class name (i.e. MasterPost => :master_post) rather
|
153
|
+
# than the :model_name resource option in order to comply with the auto-generated model attribute hash built by Rails.
|
154
|
+
# This is especially important when dealing with new, create, edit, and update actions.
|
155
|
+
def model_symbol
|
156
|
+
name = model_class.name.underscore
|
157
|
+
name ? name.to_sym : nil
|
158
|
+
end
|
159
|
+
|
160
|
+
# Answers the current model object.
|
161
|
+
def model_object
|
162
|
+
model_name ? instance_variable_get("@#{model_name}") : nil
|
163
|
+
end
|
164
|
+
|
165
|
+
# Answers the controller symbol
|
166
|
+
def controller_symbol suffix = nil
|
167
|
+
[self.class.to_s.underscore.gsub('/', '_').chomp("_controller"), suffix].compact.join('_').to_sym
|
168
|
+
end
|
169
|
+
|
170
|
+
# Convenience method for answering back a properly camelized controller name.
|
171
|
+
def camelize_controller_name name
|
172
|
+
name = name.gsub(/^(\w)/) {|c| c.capitalize}
|
173
|
+
name += "Controller" unless name.include? "Controller"
|
174
|
+
name
|
175
|
+
end
|
176
|
+
|
177
|
+
# Builds all resources for the controller(s).
|
178
|
+
def build_resources
|
179
|
+
@resources ||= []
|
180
|
+
if @resources.empty?
|
181
|
+
add_resource self.class.name, @resources
|
182
|
+
@resources.reverse!
|
183
|
+
end
|
184
|
+
# Convenience for accessing the current model object.
|
185
|
+
instance_variable_set "@#{model_name}", @resources.last[:model_object] if model_name
|
186
|
+
end
|
187
|
+
|
188
|
+
# Answers the child or parent controller namespace (array) and name (string).
|
189
|
+
# Accepts the following argruments:
|
190
|
+
# * *full_name* - The fully namespaced controller (i.e. PostsController) or parent name (i.e. protected_pages).
|
191
|
+
# Usage:
|
192
|
+
# * Input: Public::PostsController, Output: [Public], "PostsController"
|
193
|
+
# * Input: member_manage_posts, Output: [Member, Manage], "PostsController"
|
194
|
+
# * Input: posts, Output: nil, "PostsController"
|
195
|
+
def get_controller_namespaces_and_name full_name
|
196
|
+
if full_name
|
197
|
+
delimiter = full_name.include?("Controller") ? "::" : '_'
|
198
|
+
if full_name.include? delimiter
|
199
|
+
namespaces = full_name.split delimiter
|
200
|
+
name = camelize_controller_name namespaces.pop
|
201
|
+
return namespaces.collect(&:capitalize), name
|
202
|
+
else
|
203
|
+
return nil, camelize_controller_name(full_name)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Recursively walks the controller belongs_to hierarchy (if any) adding new resources along the way.
|
209
|
+
def add_resource controller_name, resources
|
210
|
+
logger.debug "Adding resource '#{controller_name}' to resources (size = #{resources.size})."
|
211
|
+
resource = configure_resource controller_name
|
212
|
+
if resource
|
213
|
+
resources << resource
|
214
|
+
# Recursively add parents (if any).
|
215
|
+
if resource[:controller_class].methods.include? "parent_resource"
|
216
|
+
add_resource resource[:controller_class].parent_resource, resources
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Configures a resource via belongs_to name refrence in controller. By default the controller and model
|
222
|
+
# are assumed to use the same root name regardless of singular or plural context.
|
223
|
+
def configure_resource controller_name
|
224
|
+
namespaces, controller_name = get_controller_namespaces_and_name controller_name
|
225
|
+
controller_class = [namespaces, controller_name].compact.join("::").constantize
|
226
|
+
controller_name = controller_name.chomp("Controller").underscore
|
227
|
+
parent_key = controller_name.singularize + "_id"
|
228
|
+
resource = controller_class.resource_options || {}
|
229
|
+
resource.reverse_merge! :parent_key => parent_key,
|
230
|
+
:parent_id => params[parent_key],
|
231
|
+
:controller_name => controller_name,
|
232
|
+
:controller_class => controller_class,
|
233
|
+
:label => controller_name.capitalize,
|
234
|
+
:model_name => controller_name.singularize,
|
235
|
+
:namespaces => (namespaces.collect(&:downcase) if namespaces),
|
236
|
+
:new_or_edit_template => '/' + [namespaces, controller_name, "new_or_edit"].compact.join('/').downcase
|
237
|
+
begin
|
238
|
+
resource.reverse_merge! :model_class => controller_name.singularize.camelize.constantize
|
239
|
+
rescue NameError
|
240
|
+
logger.warn "Unable to constantize: " + controller_name
|
241
|
+
end
|
242
|
+
add_model_object resource
|
243
|
+
end
|
244
|
+
|
245
|
+
# Adds the current model object to the resource based on position in relationship chain.
|
246
|
+
def add_model_object resource
|
247
|
+
if resource[:model_class]
|
248
|
+
if params.include? resource[:parent_key]
|
249
|
+
# Nested parent.
|
250
|
+
resource[:model_object] = resource[:model_class].find resource[:parent_id] if resource[:parent_id]
|
251
|
+
else
|
252
|
+
# Single resource and/or end of nested chain.
|
253
|
+
resource[:model_object] = params[:id] ? resource[:model_class].find(params[:id]) : resource[:model_class].new
|
254
|
+
end
|
255
|
+
else
|
256
|
+
logger.error "Invalid model class. Check that your controller and model are of the same name, otherwise specify the model as a resource option."
|
257
|
+
end
|
258
|
+
resource
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|