resource_controller 0.4.9 → 0.5.0
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/README.rdoc +37 -1
- data/Rakefile +2 -2
- data/lib/resource_controller.rb +10 -5
- data/lib/resource_controller/class_methods.rb +3 -1
- data/lib/resource_controller/controller.rb +6 -0
- data/lib/resource_controller/helpers/nested.rb +21 -3
- data/lib/resource_controller/helpers/singleton_customizations.rb +60 -0
- data/lib/resource_controller/helpers/urls.rb +5 -1
- data/lib/resource_controller/singleton.rb +15 -0
- data/lib/resource_controller/version.rb +2 -2
- data/test/app/controllers/accounts_controller.rb +6 -0
- data/test/app/controllers/cms/products_controller.rb +1 -1
- data/test/app/controllers/images_controller.rb +4 -0
- data/test/app/controllers/options_controller.rb +8 -0
- data/test/app/helpers/accounts_helper.rb +2 -0
- data/test/app/helpers/images_helper.rb +2 -0
- data/test/app/models/account.rb +1 -0
- data/test/app/models/image.rb +3 -0
- data/test/app/models/user.rb +3 -0
- data/test/app/views/accounts/_form.html.erb +4 -0
- data/test/app/views/accounts/edit.html.erb +14 -0
- data/test/app/views/accounts/new.html.erb +12 -0
- data/test/app/views/accounts/show.html.erb +5 -0
- data/test/app/views/images/_form.html.erb +4 -0
- data/test/app/views/images/edit.html.erb +14 -0
- data/test/app/views/images/new.html.erb +12 -0
- data/test/app/views/options/_form.html.erb +8 -0
- data/test/app/views/options/edit.html.erb +16 -0
- data/test/app/views/options/index.html.erb +21 -0
- data/test/app/views/options/new.html.erb +12 -0
- data/test/app/views/options/show.html.erb +10 -0
- data/test/config/database.yml +0 -3
- data/test/config/environment.rb +2 -2
- data/test/config/routes.rb +8 -1
- data/test/db/migrate/002_create_products.rb +1 -1
- data/test/db/migrate/004_create_options.rb +3 -2
- data/test/db/migrate/011_create_images.rb +12 -0
- data/test/db/migrate/012_create_users.rb +11 -0
- data/test/db/schema.rb +13 -6
- data/test/log/development.log +84 -0
- data/test/log/test.log +4880 -0
- data/test/test/fixtures/images.yml +6 -0
- data/test/test/fixtures/users.yml +5 -0
- data/test/test/functional/images_controller_test.rb +37 -0
- data/test/test/unit/helpers/current_objects_test.rb +6 -0
- data/test/test/unit/helpers/nested_test.rb +5 -1
- data/test/test/unit/helpers/singleton_current_objects_test.rb +68 -0
- data/test/test/unit/helpers/singleton_nested_test.rb +77 -0
- data/test/test/unit/helpers/singleton_urls_test.rb +67 -0
- data/test/test/unit/helpers/urls_test.rb +5 -1
- data/test/test/unit/image_test.rb +7 -0
- metadata +35 -5
- data/README +0 -282
- data/lib/tasks/gem.rake +0 -67
data/README.rdoc
CHANGED
@@ -102,6 +102,42 @@ With actions that can fail, the scoping defaults to success. That means that cr
|
|
102
102
|
end
|
103
103
|
|
104
104
|
end
|
105
|
+
|
106
|
+
== Singleton Resource
|
107
|
+
|
108
|
+
If you want to create a singleton RESTful controller inherit from ResourceController::Singleton.
|
109
|
+
|
110
|
+
class AccountsController < ResourceController::Singleton
|
111
|
+
end
|
112
|
+
|
113
|
+
*Note:* This type of controllers handle a single resource only so the index action and all the collection helpers (collection_url, collection_path...) are not available for them.
|
114
|
+
|
115
|
+
Loading objects in singletons is similar to plural controllers with one exception. For non-nested singleton controllers you should override the object method as it defaults to nil for them.
|
116
|
+
|
117
|
+
class AccountsController < ResourceController::Singleton
|
118
|
+
private
|
119
|
+
def object
|
120
|
+
@object ||= Account.find(session[:account_id])
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
In other cases you can use the default logic and override it only if you use permalinks or anything special.
|
125
|
+
|
126
|
+
Singleton nesting with both :has_many and :has_one associations is provided...
|
127
|
+
|
128
|
+
map.resource :account, :has_many => :options # /account/options, account is a singleton parent
|
129
|
+
map.resources :users, :has_one => :image # /users/1/image, image is a singleton child
|
130
|
+
|
131
|
+
If you have the :has_many association with a singleton parent remember to override parent_object for your :has_many controller as it returns nil by default in this case.
|
132
|
+
|
133
|
+
class OptionsController < ResourceController::Base
|
134
|
+
belongs_to :account
|
135
|
+
|
136
|
+
protected
|
137
|
+
def parent_object
|
138
|
+
Account.find(session[:account_id])
|
139
|
+
end
|
140
|
+
end
|
105
141
|
|
106
142
|
== Helpers (ResourceController::Helpers)
|
107
143
|
|
@@ -279,4 +315,4 @@ resource_controller was created, and is maintained by {James Golick}[http://jame
|
|
279
315
|
|
280
316
|
== License
|
281
317
|
|
282
|
-
resource_controller is available under the {MIT License}[http://en.wikipedia.org/wiki/MIT_License]
|
318
|
+
resource_controller is available under the {MIT License}[http://en.wikipedia.org/wiki/MIT_License]
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require 'rake'
|
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
require File.dirname(__FILE__)+'/lib/resource_controller/version'
|
5
|
-
Dir['
|
5
|
+
Dir['tasks/**.rake'].each { |tasks| load tasks }
|
6
6
|
|
7
7
|
desc 'Default: run unit tests.'
|
8
8
|
task :default => :test
|
@@ -19,7 +19,7 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
19
19
|
rdoc.rdoc_dir = 'rdoc'
|
20
20
|
rdoc.title = 'ResourceController'
|
21
21
|
rdoc.options << '--line-numbers' << '--inline-source'
|
22
|
-
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('README.rdoc')
|
23
23
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
24
24
|
end
|
25
25
|
|
data/lib/resource_controller.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
module ResourceController
|
2
|
-
ACTIONS
|
3
|
-
|
4
|
-
|
2
|
+
ACTIONS = [:index, :show, :new_action, :create, :edit, :update, :destroy].freeze
|
3
|
+
SINGLETON_ACTIONS = (ACTIONS - [:index]).freeze
|
4
|
+
FAILABLE_ACTIONS = ACTIONS - [:index, :new_action, :edit].freeze
|
5
|
+
NAME_ACCESSORS = [:model_name, :route_name, :object_name]
|
5
6
|
|
6
7
|
module ActionControllerExtension
|
7
8
|
unloadable
|
8
9
|
|
9
|
-
def resource_controller
|
10
|
+
def resource_controller(*args)
|
10
11
|
include ResourceController::Controller
|
11
|
-
|
12
|
+
|
13
|
+
if args.include?(:singleton)
|
14
|
+
include ResourceController::Helpers::SingletonCustomizations
|
15
|
+
end
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
@@ -10,8 +10,10 @@ module ResourceController
|
|
10
10
|
config = {}
|
11
11
|
config.merge!(opts.pop) if opts.last.is_a?(Hash)
|
12
12
|
|
13
|
+
all_actions = (singleton? ? ResourceController::SINGLETON_ACTIONS : ResourceController::ACTIONS) - [:new_action] + [:new]
|
14
|
+
|
13
15
|
actions_to_remove = []
|
14
|
-
actions_to_remove +=
|
16
|
+
actions_to_remove += all_actions - opts unless opts.first == :all
|
15
17
|
actions_to_remove += [*config[:except]] if config[:except]
|
16
18
|
actions_to_remove.uniq!
|
17
19
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Nested and Polymorphic Resource Helpers
|
2
2
|
#
|
3
3
|
module ResourceController::Helpers::Nested
|
4
|
-
protected
|
4
|
+
protected
|
5
5
|
# Returns the relevant association proxy of the parent. (i.e. /posts/1/comments # => @post.comments)
|
6
6
|
#
|
7
7
|
def parent_association
|
@@ -11,7 +11,19 @@ module ResourceController::Helpers::Nested
|
|
11
11
|
# Returns the type of the current parent
|
12
12
|
#
|
13
13
|
def parent_type
|
14
|
-
@parent_type ||=
|
14
|
+
@parent_type ||= parent_type_from_params || parent_type_from_request
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the type of the current parent extracted from params
|
18
|
+
#
|
19
|
+
def parent_type_from_params
|
20
|
+
[*belongs_to].find { |parent| !params["#{parent}_id".to_sym].nil? }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the type of the current parent extracted form a request path
|
24
|
+
#
|
25
|
+
def parent_type_from_request
|
26
|
+
[*belongs_to].find { |parent| request.path.split('/').include? parent.to_s }
|
15
27
|
end
|
16
28
|
|
17
29
|
# Returns true/false based on whether or not a parent is present.
|
@@ -20,6 +32,12 @@ module ResourceController::Helpers::Nested
|
|
20
32
|
!parent_type.nil?
|
21
33
|
end
|
22
34
|
|
35
|
+
# Returns true/false based on whether or not a parent is a singleton.
|
36
|
+
#
|
37
|
+
def parent_singleton?
|
38
|
+
!parent_type_from_request.nil?
|
39
|
+
end
|
40
|
+
|
23
41
|
# Returns the current parent param, if there is a parent. (i.e. params[:post_id])
|
24
42
|
def parent_param
|
25
43
|
params["#{parent_type}_id".to_sym]
|
@@ -34,7 +52,7 @@ module ResourceController::Helpers::Nested
|
|
34
52
|
# Returns the current parent object if a parent object is present.
|
35
53
|
#
|
36
54
|
def parent_object
|
37
|
-
parent? ? parent_model.find(parent_param) : nil
|
55
|
+
parent? && !parent_singleton? ? parent_model.find(parent_param) : nil
|
38
56
|
end
|
39
57
|
|
40
58
|
# If there is a parent, returns the relevant association proxy. Otherwise returns model.
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Singleton Resource Helpers
|
2
|
+
#
|
3
|
+
# Used internally to transform a plural RESTful controller into a singleton
|
4
|
+
#
|
5
|
+
module ResourceController::Helpers::SingletonCustomizations
|
6
|
+
def self.included(subclass)
|
7
|
+
subclass.class_eval do
|
8
|
+
methods_to_undefine = [:param, :index, :collection, :load_collection, :collection_url,
|
9
|
+
:collection_path, :hash_for_collection_url, :hash_for_collection_path]
|
10
|
+
methods_to_undefine.each { |method| undef_method(method) if method_defined? method }
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def singleton?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
# Used to fetch the current object in a singleton controller.
|
22
|
+
#
|
23
|
+
# By defult this method is able to fetch the current object for resources nested with the :has_one association only. (i.e. /users/1/image # => @user.image)
|
24
|
+
# In other cases you should override this method and provide your custom code to fetch a singleton resource object, like using a session hash.
|
25
|
+
#
|
26
|
+
# class AccountsController < ResourceController::Singleton
|
27
|
+
# private
|
28
|
+
# def object
|
29
|
+
# @object ||= Account.find(session[:account_id])
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
def object
|
34
|
+
@object ||= parent? ? end_of_association_chain : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the :has_one association proxy of the parent. (i.e. /users/1/image # => @user.image)
|
38
|
+
#
|
39
|
+
def parent_association
|
40
|
+
@parent_association ||= parent_object.send(model_name.to_sym)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Used internally to provide the options to smart_url in a singleton controller.
|
44
|
+
#
|
45
|
+
def object_url_options(action_prefix = nil, alternate_object = nil)
|
46
|
+
[action_prefix] + namespaces + [parent_url_options, route_name.to_sym]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Builds the object, but doesn't save it, during the new, and create action.
|
50
|
+
#
|
51
|
+
def build_object
|
52
|
+
@object ||= singleton_build_object_base.send parent? ? "build_#{model_name}".to_sym : :new, object_params
|
53
|
+
end
|
54
|
+
|
55
|
+
# Singleton controllers don't build off of association proxy, so we can't use end_of_association_chain here
|
56
|
+
#
|
57
|
+
def singleton_build_object_base
|
58
|
+
parent? ? parent_object : model
|
59
|
+
end
|
60
|
+
end
|
@@ -110,7 +110,11 @@ module ResourceController::Helpers::Urls
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def parent_url_options
|
113
|
-
parent?
|
113
|
+
if parent?
|
114
|
+
parent_singleton? ? parent_type.to_sym : [parent_type.to_sym, parent_object]
|
115
|
+
else
|
116
|
+
nil
|
117
|
+
end
|
114
118
|
end
|
115
119
|
|
116
120
|
# Returns all of the current namespaces of the current controller, symbolized, in array form.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ResourceController
|
2
|
+
|
3
|
+
# == ResourceController::Singleton
|
4
|
+
#
|
5
|
+
# Inherit from this class to create your RESTful singleton controller. See the README for usage.
|
6
|
+
#
|
7
|
+
class Singleton < ApplicationController
|
8
|
+
unloadable
|
9
|
+
|
10
|
+
def self.inherited(subclass)
|
11
|
+
super
|
12
|
+
subclass.class_eval { resource_controller :singleton }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/test/app/models/account.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
<h1>Editing Account</h1>
|
2
|
+
|
3
|
+
<%= error_messages_for :account %>
|
4
|
+
|
5
|
+
<% form_for(:account, :url => object_url, :html => { :method => :put }) do |f| %>
|
6
|
+
<%= render :partial => "form", :locals => { :f => f } %>
|
7
|
+
<p>
|
8
|
+
<%=submit_tag "Update"%>
|
9
|
+
</p>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<br/>
|
13
|
+
|
14
|
+
<%= link_to 'Show', object_url %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h1>New Account</h1>
|
2
|
+
|
3
|
+
<%= error_messages_for :account %>
|
4
|
+
|
5
|
+
<% form_for(:account, :url => object_url) do |f| %>
|
6
|
+
<%= render :partial => "form", :locals => { :f => f } %>
|
7
|
+
<p>
|
8
|
+
<%= submit_tag "Create" %>
|
9
|
+
</p>
|
10
|
+
<% end %>
|
11
|
+
<br/>
|
12
|
+
<%= link_to 'Back', object_url %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h1>Editing Image</h1>
|
2
|
+
|
3
|
+
<%= error_messages_for :image %>
|
4
|
+
|
5
|
+
<% form_for(:image, :url => object_url, :html => { :method => :put }) do |f| %>
|
6
|
+
<%= render :partial => "form", :locals => { :f => f } %>
|
7
|
+
<p>
|
8
|
+
<%=submit_tag "Update"%>
|
9
|
+
</p>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<br/>
|
13
|
+
|
14
|
+
<%= link_to 'Show', object_url %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h1>New Image</h1>
|
2
|
+
|
3
|
+
<%= error_messages_for :image %>
|
4
|
+
|
5
|
+
<% form_for(:image, :url => object_url) do |f| %>
|
6
|
+
<%= render :partial => "form", :locals => { :f => f } %>
|
7
|
+
<p>
|
8
|
+
<%= submit_tag "Create" %>
|
9
|
+
</p>
|
10
|
+
<% end %>
|
11
|
+
<br/>
|
12
|
+
<%= link_to 'Back', object_url %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h1>Editing Option</h1>
|
2
|
+
|
3
|
+
<%= error_messages_for :option %>
|
4
|
+
|
5
|
+
<% form_for(:option, :url => object_url, :html => { :method => :put }) do |f| %>
|
6
|
+
<%= render :partial => "form", :locals => { :f => f } %>
|
7
|
+
<p>
|
8
|
+
<%=submit_tag "Update"%>
|
9
|
+
</p>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<br/>
|
13
|
+
|
14
|
+
<%= link_to 'Show', object_url %>
|
15
|
+
|
|
16
|
+
<%= link_to 'Back', collection_url %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h1>Listing Options</h1>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<tr>
|
5
|
+
<th>Account</th>
|
6
|
+
<th>Title</th>
|
7
|
+
</tr>
|
8
|
+
<%- @options.each do |option|%>
|
9
|
+
<tr>
|
10
|
+
<td><%=h option.account_id %></td>
|
11
|
+
<td><%=h option.title %></td>
|
12
|
+
|
13
|
+
<td><%=link_to 'Show', object_url(option) %></td>
|
14
|
+
<td><%=link_to 'Edit', edit_object_url(option) %></td>
|
15
|
+
<td><%=link_to 'Destroy', object_url(option), :confirm => 'Are you sure?', :method => :delete %></td>
|
16
|
+
</tr>
|
17
|
+
<% end %>
|
18
|
+
</table>
|
19
|
+
<br/>
|
20
|
+
|
21
|
+
<%= link_to 'New Option', new_object_url %>
|