extended_inherited_resources 0.1.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.
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "extended_inherited_resources"
8
+ gem.summary = "Slightly extended version of josevalim inherited_resources - for rails 2.3"
9
+ gem.description = ""
10
+ gem.email = "b.kosmowski@selleo.com"
11
+ gem.homepage = "http://github.com/stevo/extended_inherited_resources"
12
+ gem.authors = ["josevalim", "stevo"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "extended_inherited_resources #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,70 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{extended_inherited_resources}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["josevalim", "stevo"]
12
+ s.date = %q{2010-04-22}
13
+ s.description = %q{}
14
+ s.email = %q{b.kosmowski@selleo.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "extended_inherited_resources.gemspec",
27
+ "init.rb",
28
+ "lib/inherited_resources.rb",
29
+ "lib/inherited_resources/actions.rb",
30
+ "lib/inherited_resources/base.rb",
31
+ "lib/inherited_resources/base_helpers.rb",
32
+ "lib/inherited_resources/belongs_to_helpers.rb",
33
+ "lib/inherited_resources/blank_slate.rb",
34
+ "lib/inherited_resources/class_methods.rb",
35
+ "lib/inherited_resources/dsl.rb",
36
+ "lib/inherited_resources/legacy/respond_to.rb",
37
+ "lib/inherited_resources/legacy/responder.rb",
38
+ "lib/inherited_resources/locales/en.yml",
39
+ "lib/inherited_resources/polymorphic_helpers.rb",
40
+ "lib/inherited_resources/responder.rb",
41
+ "lib/inherited_resources/singleton_helpers.rb",
42
+ "lib/inherited_resources/url_helpers.rb",
43
+ "lib/inherited_resources/version.rb",
44
+ "test/helper.rb",
45
+ "test/test_extended_inherited_resources.rb"
46
+ ]
47
+ s.homepage = %q{http://github.com/stevo/extended_inherited_resources}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.3.6}
51
+ s.summary = %q{Slightly extended version of josevalim inherited_resources - for rails 2.3}
52
+ s.test_files = [
53
+ "test/helper.rb",
54
+ "test/test_extended_inherited_resources.rb"
55
+ ]
56
+
57
+ if s.respond_to? :specification_version then
58
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
62
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
68
+ end
69
+ end
70
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'inherited_resources'
@@ -0,0 +1,43 @@
1
+ # respond_to is the only file that should be loaded before hand. All others
2
+ # are loaded on demand.
3
+ #
4
+ unless defined?(ActionController::Responder)
5
+ require 'inherited_resources/legacy/responder'
6
+ require 'inherited_resources/legacy/respond_to'
7
+ end
8
+
9
+ require 'responders'
10
+ I18n.load_path.unshift File.expand_path(File.join(File.dirname(__FILE__), 'inherited_resources', 'locales', 'en.yml'))
11
+
12
+ module InheritedResources
13
+ ACTIONS = [ :index, :show, :new, :edit, :create, :update, :destroy ] unless self.const_defined?(:ACTIONS)
14
+
15
+ autoload :Actions, 'inherited_resources/actions'
16
+ autoload :Base, 'inherited_resources/base'
17
+ autoload :BaseHelpers, 'inherited_resources/base_helpers'
18
+ autoload :BelongsToHelpers, 'inherited_resources/belongs_to_helpers'
19
+ autoload :ClassMethods, 'inherited_resources/class_methods'
20
+ autoload :DSL, 'inherited_resources/dsl'
21
+ autoload :PolymorphicHelpers, 'inherited_resources/polymorphic_helpers'
22
+ autoload :SingletonHelpers, 'inherited_resources/singleton_helpers'
23
+ autoload :UrlHelpers, 'inherited_resources/url_helpers'
24
+ autoload :VERSION, 'inherited_resources/version'
25
+
26
+ # Change the flash keys used by FlashResponder.
27
+ def self.flash_keys=(array)
28
+ Responders::FlashResponder.flash_keys = array
29
+ end
30
+ end
31
+
32
+ class ActionController::Base
33
+ public :flash, :render
34
+
35
+ # If you cannot inherit from InheritedResources::Base you can call
36
+ # inherit_resource in your controller to have all the required modules and
37
+ # funcionality included.
38
+ def self.inherit_resources
39
+ InheritedResources::Base.inherit_resources(self)
40
+ initialize_resources_class_accessors!
41
+ create_resources_url_helpers!
42
+ end
43
+ end
@@ -0,0 +1,67 @@
1
+ module InheritedResources
2
+ # Holds all default actions for InheritedResouces.
3
+ module Actions
4
+
5
+ # GET /resources
6
+ def index(&block)
7
+ respond_with(*with_chain(collection), &block)
8
+ end
9
+ alias :index! :index
10
+
11
+ # GET /resources/1
12
+ def show(&block)
13
+ respond_with(*with_chain(resource), &block)
14
+ end
15
+ alias :show! :show
16
+
17
+ # GET /resources/new
18
+ def new(&block)
19
+ respond_with(*with_chain(build_resource), &block)
20
+ end
21
+ alias :new! :new
22
+
23
+ # GET /resources/1/edit
24
+ def edit(&block)
25
+ respond_with(*with_chain(resource), &block)
26
+ end
27
+ alias :edit! :edit
28
+
29
+ # POST /resources
30
+ def create(options={}, &block)
31
+ object = build_resource
32
+
33
+ if create_resource(object)
34
+ options[:location] ||= (configured_redirects(:create) || resource_url) rescue nil
35
+ end
36
+
37
+ respond_with_dual_blocks(object, options, &block)
38
+ end
39
+ alias :create! :create
40
+
41
+ # PUT /resources/1
42
+ def update(options={}, &block)
43
+ object = resource
44
+
45
+ if update_resource(object, params[resource_instance_name])
46
+ options[:location] ||= (configured_redirects(:update) || resource_url) rescue nil
47
+ end
48
+
49
+ respond_with_dual_blocks(object, options, &block)
50
+ end
51
+ alias :update! :update
52
+
53
+ # DELETE /resources/1
54
+ def destroy(options={}, &block)
55
+ object = resource
56
+ options[:location] ||= collection_url rescue nil
57
+
58
+ destroy_resource(object)
59
+ respond_with_dual_blocks(object, options, &block)
60
+ end
61
+ alias :destroy! :destroy
62
+
63
+ # Make aliases protected
64
+ protected :index!, :show!, :new!, :create!, :edit!, :update!, :destroy!
65
+ end
66
+ end
67
+
@@ -0,0 +1,47 @@
1
+ require 'inherited_resources/blank_slate'
2
+ require 'inherited_resources/responder'
3
+
4
+ module InheritedResources
5
+ # = Base
6
+ #
7
+ # This is the base class that holds all actions. If you see the code for each
8
+ # action, they are quite similar to Rails default scaffold.
9
+ #
10
+ # To change your base behavior, you can overwrite your actions and call super,
11
+ # call <tt>default</tt> class method, call <<tt>actions</tt> class method
12
+ # or overwrite some helpers in the base_helpers.rb file.
13
+ #
14
+ class Base < ::ApplicationController
15
+ unloadable
16
+
17
+ # Overwrite inherit_resources to add specific InheritedResources behavior.
18
+ #
19
+ def self.inherit_resources(base)
20
+ base.class_eval do
21
+ include InheritedResources::Actions
22
+ include InheritedResources::BaseHelpers
23
+ extend InheritedResources::ClassMethods
24
+ extend InheritedResources::UrlHelpers
25
+
26
+ # Add at least :html mime type
27
+ respond_to :html
28
+ self.responder = InheritedResources::Responder
29
+
30
+ helper_method :collection_url, :collection_path, :resource_url, :resource_path,
31
+ :new_resource_url, :new_resource_path, :edit_resource_url, :edit_resource_path,
32
+ :parent_url, :parent_path, :resource, :collection, :resource_class, :association_chain,
33
+ :resource_instance_name, :resource_collection_name
34
+
35
+ base.with_options :instance_writer => false do |c|
36
+ c.class_inheritable_accessor :resource_class, :redirects
37
+ c.class_inheritable_array :parents_symbols
38
+ c.class_inheritable_hash :resources_configuration
39
+ end
40
+
41
+ protected :resource_class, :parents_symbols, :resources_configuration
42
+ end
43
+ end
44
+
45
+ inherit_resources(self)
46
+ end
47
+ end
@@ -0,0 +1,284 @@
1
+ # Whenever base is required load the dumb responder since it's used inside actions.
2
+ require 'inherited_resources/blank_slate'
3
+
4
+ module InheritedResources
5
+ # Base helpers for InheritedResource work. Some methods here can be overwriten
6
+ # and you will need to do that to customize your controllers from time to time.
7
+ #
8
+ module BaseHelpers
9
+
10
+ protected
11
+
12
+ def configured_redirects(for_action)
13
+
14
+ case self.class.redirects[for_action.to_sym]
15
+ when :index then
16
+ collection_url
17
+ when :edit then
18
+ edit_resource_url
19
+ when :show then
20
+ resource_url
21
+ when :root
22
+ root_url
23
+ end
24
+ end
25
+
26
+ # This is how the collection is loaded.
27
+ #
28
+ # You might want to overwrite this method if you want to add pagination
29
+ # for example. When you do that, don't forget to cache the result in an
30
+ # instance_variable:
31
+ #
32
+ # def collection
33
+ # @projects ||= end_of_association_chain.paginate(params[:page]).all
34
+ # end
35
+ #
36
+ def collection
37
+ get_collection_ivar || set_collection_ivar(end_of_association_chain.find(:all))
38
+ end
39
+
40
+ # This is how the resource is loaded.
41
+ #
42
+ # You might want to overwrite this method when you are using permalink.
43
+ # When you do that, don't forget to cache the result in an
44
+ # instance_variable:
45
+ #
46
+ # def resource
47
+ # @project ||= end_of_association_chain.find_by_permalink!(params[:id])
48
+ # end
49
+ #
50
+ # You also might want to add the exclamation mark at the end of the method
51
+ # because it will raise a 404 if nothing can be found. Otherwise it will
52
+ # probably render a 500 error message.
53
+ #
54
+ def resource
55
+ get_resource_ivar || set_resource_ivar(end_of_association_chain.find(params[:id]))
56
+ end
57
+
58
+ # This method is responsable for building the object on :new and :create
59
+ # methods. If you overwrite it, don't forget to cache the result in an
60
+ # instance variable.
61
+ #
62
+ def build_resource
63
+ get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_build, params[resource_instance_name] || {}))
64
+ end
65
+
66
+ # Responsible for saving the resource on :create method. Overwriting this
67
+ # allow you to control the way resource is saved. Let's say you have a
68
+ # PassworsController who is responsible for finding an user by email and
69
+ # sent password instructions for him. Instead of overwriting the entire
70
+ # :create method, you could do something:
71
+ #
72
+ # def create_resource(object)
73
+ # object.send_instructions_by_email
74
+ # end
75
+ #
76
+ def create_resource(object)
77
+ object.save
78
+ end
79
+
80
+ # Responsible for updating the resource in :update method. This allow you
81
+ # to handle how the resource is gona be updated, let's say in a different
82
+ # way then the usual :update_attributes:
83
+ #
84
+ # def update_resource(object, attributes)
85
+ # object.reset_password!(attributes)
86
+ # end
87
+ #
88
+ def update_resource(object, attributes)
89
+ object.update_attributes(attributes)
90
+ end
91
+
92
+ # Handle the :destroy method for the resource. Overwrite it to call your
93
+ # own method for destroing the resource, as:
94
+ #
95
+ # def destroy_resource(object)
96
+ # object.cancel
97
+ # end
98
+ #
99
+ def destroy_resource(object)
100
+ object.destroy
101
+ end
102
+
103
+ # This class allows you to set a instance variable to begin your
104
+ # association chain. For example, usually your projects belongs to users
105
+ # and that means that they belong to the current logged in user. So you
106
+ # could do this:
107
+ #
108
+ # def begin_of_association_chain
109
+ # @current_user
110
+ # end
111
+ #
112
+ # So every time we instantiate a project, we will do:
113
+ #
114
+ # @current_user.projects.build(params[:project])
115
+ # @current_user.projects.find(params[:id])
116
+ #
117
+ # The variable set in begin_of_association_chain is not sent when building
118
+ # urls, so this is never going to happen when calling resource_url:
119
+ #
120
+ # project_url(@current_user, @project)
121
+ #
122
+ # If the user actually scopes the url, you should use belongs_to method
123
+ # and declare that projects belong to user.
124
+ #
125
+ def begin_of_association_chain
126
+ nil
127
+ end
128
+
129
+ # Returns if the controller has a parent. When only base helpers are loaded,
130
+ # it's always false and should not be overwriten.
131
+ #
132
+ def parent?
133
+ false
134
+ end
135
+
136
+ # Returns the association chain, with all parents (does not include the
137
+ # current resource).
138
+ #
139
+ def association_chain
140
+ @association_chain ||=
141
+ symbols_for_association_chain.inject([begin_of_association_chain]) do |chain, symbol|
142
+ chain << evaluate_parent(symbol, resources_configuration[symbol], chain.last)
143
+ end.compact.freeze
144
+ end
145
+
146
+ # Overwrite this method to provide other interpolation options when
147
+ # the flash message is going to be set.
148
+ #
149
+ # def interpolation_options
150
+ # { }
151
+ # end
152
+
153
+ private
154
+
155
+ # Adds the given object to association chain.
156
+ def with_chain(object)
157
+ association_chain + [ object ]
158
+ end
159
+
160
+ # Fast accessor to resource_collection_name
161
+ #
162
+ def resource_collection_name #:nodoc:
163
+ self.resources_configuration[:self][:collection_name]
164
+ end
165
+
166
+ # Fast accessor to resource_instance_name
167
+ #
168
+ def resource_instance_name #:nodoc:
169
+ self.resources_configuration[:self][:instance_name]
170
+ end
171
+
172
+ # This methods gets your begin_of_association_chain, join it with your
173
+ # parents chain and returns the scoped association.
174
+ #
175
+ def end_of_association_chain #:nodoc:
176
+ if chain = association_chain.last
177
+ if method_for_association_chain
178
+ apply_scopes_if_available(chain.send(method_for_association_chain))
179
+ else
180
+ # This only happens when we specify begin_of_association_chain in
181
+ # a singletion controller without parents. In this case, the chain
182
+ # is exactly the begin_of_association_chain which is already an
183
+ # instance and then not scopable.
184
+ chain
185
+ end
186
+ else
187
+ apply_scopes_if_available(resource_class)
188
+ end
189
+ end
190
+
191
+ # Returns the appropriated method to build the resource.
192
+ #
193
+ def method_for_build #:nodoc:
194
+ (begin_of_association_chain || parent?) ? method_for_association_build : :new
195
+ end
196
+
197
+ # Returns the name of the method used for build the resource in cases
198
+ # where we have a parent. This is overwritten in singleton scenarios.
199
+ #
200
+ def method_for_association_build
201
+ :build
202
+ end
203
+
204
+ # Returns the name of the method to be called, before returning the end
205
+ # of the association chain. This is overwriten by singleton cases
206
+ # where no method for association chain is called.
207
+ #
208
+ def method_for_association_chain #:nodoc:
209
+ resource_collection_name
210
+ end
211
+
212
+ # Get resource ivar based on the current resource controller.
213
+ #
214
+ def get_resource_ivar #:nodoc:
215
+ instance_variable_get("@#{resource_instance_name}")
216
+ end
217
+
218
+ # Set resource ivar based on the current resource controller.
219
+ #
220
+ def set_resource_ivar(resource) #:nodoc:
221
+ instance_variable_set("@#{resource_instance_name}", resource)
222
+ end
223
+
224
+ # Get collection ivar based on the current resource controller.
225
+ #
226
+ def get_collection_ivar #:nodoc:
227
+ instance_variable_get("@#{resource_collection_name}")
228
+ end
229
+
230
+ # Set collection ivar based on the current resource controller.
231
+ #
232
+ def set_collection_ivar(collection) #:nodoc:
233
+ instance_variable_set("@#{resource_collection_name}", collection)
234
+ end
235
+
236
+ # Used to allow to specify success and failure within just one block:
237
+ #
238
+ # def create
239
+ # create! do |success, failure|
240
+ # failure.html { redirect_to root_url }
241
+ # end
242
+ # end
243
+ #
244
+ # It also calculates the response url in case a block without arity is
245
+ # given and returns it. Otherwise returns nil.
246
+ #
247
+ def respond_with_dual_blocks(object, options, &block) #:nodoc:
248
+ args = (with_chain(object) << options)
249
+
250
+ case block.try(:arity)
251
+ when 2
252
+ respond_with(*args) do |responder|
253
+ blank_slate = InheritedResources::BlankSlate.new
254
+ if object.errors.empty?
255
+ block.call(responder, blank_slate)
256
+ else
257
+ block.call(blank_slate, responder)
258
+ end
259
+ end
260
+ when 1
261
+ respond_with(*args, &block)
262
+ else
263
+ options[:location] = block.call if block
264
+ respond_with(*args)
265
+ end
266
+ end
267
+
268
+ # Hook to apply scopes. By default returns only the target_object given.
269
+ # It's extend by HasScopeHelpers.
270
+ #
271
+ def apply_scopes_if_available(target_object) #:nodoc:
272
+ respond_to?(:apply_scopes) ? apply_scopes(target_object) : target_object
273
+ end
274
+
275
+ # Symbols chain in base helpers return nothing. This is later overwriten
276
+ # by belongs_to and can be complex in polymorphic cases.
277
+ #
278
+ def symbols_for_association_chain #:nodoc:
279
+ []
280
+ end
281
+
282
+ end
283
+ end
284
+