acts_as_multipart_form 0.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.
Files changed (86) hide show
  1. data/CHANGELOG +3 -0
  2. data/Gemfile +27 -0
  3. data/Gemfile.lock +157 -0
  4. data/LICENSE.txt +20 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +65 -0
  8. data/VERSION +1 -0
  9. data/acts_as_multipart_form.gemspec +163 -0
  10. data/app/controllers/multipart_form/in_progress_forms_controller.rb +0 -0
  11. data/app/models/multipart_form/in_progress_form.rb +20 -0
  12. data/app/views/multipart_form/_breadcrumb.html.erb +21 -0
  13. data/app/views/multipart_form/_index_links.html.erb +20 -0
  14. data/app/views/multipart_form/in_progress_form/index.html.erb +0 -0
  15. data/app/views/multipart_form/in_progress_form/index.html.haml +0 -0
  16. data/lib/acts_as_multipart_form.rb +2 -0
  17. data/lib/acts_as_multipart_form/config.rb +36 -0
  18. data/lib/acts_as_multipart_form/engine.rb +4 -0
  19. data/lib/acts_as_multipart_form/multipart_form_in_controller.rb +301 -0
  20. data/lib/acts_as_multipart_form/multipart_form_in_model.rb +105 -0
  21. data/lib/acts_as_multipart_form/railtie.rb +14 -0
  22. data/lib/generators/acts_as_multipart_form/install_generator.rb +44 -0
  23. data/lib/generators/acts_as_multipart_form/templates/config.rb +6 -0
  24. data/lib/generators/acts_as_multipart_form/templates/migrations/install_migration.rb.erb +17 -0
  25. data/spec/acts_as_multipart_form_spec.rb +7 -0
  26. data/spec/dummy/Rakefile +7 -0
  27. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  28. data/spec/dummy/app/controllers/people_controller.rb +53 -0
  29. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec/dummy/app/models/person.rb +5 -0
  31. data/spec/dummy/app/models/person_with_multiple_actsas.rb +5 -0
  32. data/spec/dummy/app/models/person_with_multiple_forms.rb +4 -0
  33. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  34. data/spec/dummy/app/views/people/_job_info.html.erb +8 -0
  35. data/spec/dummy/app/views/people/_person_info.html.erb +8 -0
  36. data/spec/dummy/app/views/people/hire_form.html.erb +10 -0
  37. data/spec/dummy/app/views/people/index.html.erb +16 -0
  38. data/spec/dummy/app/views/people/show.html.erb +0 -0
  39. data/spec/dummy/config.ru +4 -0
  40. data/spec/dummy/config/application.rb +45 -0
  41. data/spec/dummy/config/boot.rb +10 -0
  42. data/spec/dummy/config/database.yml +22 -0
  43. data/spec/dummy/config/environment.rb +5 -0
  44. data/spec/dummy/config/environments/development.rb +26 -0
  45. data/spec/dummy/config/environments/production.rb +49 -0
  46. data/spec/dummy/config/environments/test.rb +35 -0
  47. data/spec/dummy/config/initializers/acts_as_multipart_form.rb +6 -0
  48. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  49. data/spec/dummy/config/initializers/inflections.rb +10 -0
  50. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  51. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  52. data/spec/dummy/config/initializers/session_store.rb +8 -0
  53. data/spec/dummy/config/locales/en.yml +5 -0
  54. data/spec/dummy/config/routes.rb +66 -0
  55. data/spec/dummy/db/migrate/20110715180834_create_people.rb +13 -0
  56. data/spec/dummy/db/migrate/20110722130249_create_multipart_form_tables.rb +17 -0
  57. data/spec/dummy/db/schema.rb +31 -0
  58. data/spec/dummy/features/form_breadcrumb.feature +75 -0
  59. data/spec/dummy/features/form_submission.feature +23 -0
  60. data/spec/dummy/features/index_links.feature +56 -0
  61. data/spec/dummy/features/step_definitions/acts_as_multipart_form_steps.rb +30 -0
  62. data/spec/dummy/features/step_definitions/config_steps.rb +23 -0
  63. data/spec/dummy/features/step_definitions/web_steps.rb +214 -0
  64. data/spec/dummy/features/support/env.rb +15 -0
  65. data/spec/dummy/features/support/paths.rb +31 -0
  66. data/spec/dummy/features/support/selectors.rb +39 -0
  67. data/spec/dummy/public/404.html +26 -0
  68. data/spec/dummy/public/422.html +26 -0
  69. data/spec/dummy/public/500.html +26 -0
  70. data/spec/dummy/public/favicon.ico +0 -0
  71. data/spec/dummy/public/javascripts/application.js +2 -0
  72. data/spec/dummy/public/javascripts/controls.js +965 -0
  73. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  74. data/spec/dummy/public/javascripts/effects.js +1123 -0
  75. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  76. data/spec/dummy/public/javascripts/rails.js +191 -0
  77. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  78. data/spec/dummy/script/rails +6 -0
  79. data/spec/in_progress_form_spec.rb +43 -0
  80. data/spec/integration/navigation_spec.rb +9 -0
  81. data/spec/multipart_form_in_controller_integeration_spec.rb +23 -0
  82. data/spec/multipart_form_in_controller_spec.rb +360 -0
  83. data/spec/multipart_form_in_model_integration_spec.rb +30 -0
  84. data/spec/multipart_form_in_model_spec.rb +156 -0
  85. data/spec/spec_helper.rb +38 -0
  86. metadata +296 -0
@@ -0,0 +1,20 @@
1
+ module MultipartForm
2
+ # Stores information about multipart forms in progress
3
+ # Useful when displaying information about the form especially when a user
4
+ # stops halfway through a form and comes back to it
5
+ #
6
+ # form_subject is a polymorphic relationship to the model that uses the form
7
+ #
8
+ # form_name relates to the name of the form on the model on the line
9
+ # acts_as_multipart_form :form_name => {:type => ...
10
+ # @author Jeremiah Hemphill
11
+ class InProgressForm < ::ActiveRecord::Base
12
+ set_table_name "multipart_form_in_progress_forms"
13
+ belongs_to :form_subject, :polymorphic => true
14
+
15
+ validates_presence_of :form_subject
16
+ validates_presence_of :form_name
17
+ validates_presence_of :last_completed_step
18
+ validates_inclusion_of :completed, :in => [true, false]
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ <div class='multipart_form_breadcrumb'>
2
+ <% if ActsAsMultipartForm.config.show_previous_next_links %>
3
+ <div class='multipart_form_breadcrumb_previous'>
4
+ <%= link_to "Previous", send(@multipart_form_path, :id => @form_subject.id, :multipart_form_part => @previous_multipart_form_part ) %>
5
+ </div>
6
+ <% end %>
7
+ <div class='multipart_form_breadcrumb_parts'>
8
+ <% @available_multipart_form_parts.each do |part| %>
9
+ <% if part[:name].to_s != @multipart_form_part.to_s %>
10
+ <%= link_to part[:name].to_s.titleize, send(@multipart_form_path, :id => @form_subject.id, :multipart_form_part => part[:name]) %>
11
+ <% else %>
12
+ <%= part[:name].to_s.titleize %>
13
+ <% end %>
14
+ <% end %>
15
+ </div>
16
+ <% if ActsAsMultipartForm.config.show_previous_next_links %>
17
+ <div class='multipart_form_breadcrumb_next'>
18
+ <%= link_to "Next", send(@multipart_form_path, :id => @form_subject.id, :multipart_form_part => @next_multipart_form_part ) %>
19
+ </div>
20
+ <% end %>
21
+ </div>
@@ -0,0 +1,20 @@
1
+ <div class='multipart_form_index_links'>
2
+ <div class='multipart_form_index_links_links'>
3
+ <% @multipart_form_index_parts[locals[:form_subject].id][:parts].each do |part| %>
4
+ <% if ActsAsMultipartForm.config.use_numbered_parts_on_index %>
5
+ <%= link_to part[:number].to_s, send(@multipart_form_path, :id => locals[:form_subject].id, :multipart_form_part => part[:name]) %>
6
+ <% else %>
7
+ <%= link_to part[:name].to_s.titleize, send(@multipart_form_path, :id => locals[:form_subject].id, :multipart_form_part => part[:name]) %>
8
+ <% end %>
9
+ <% end %>
10
+ </div>
11
+ <% if ActsAsMultipartForm.config.show_completed %>
12
+ <div class='multipart_form_index_links_complete'>
13
+ <% if @multipart_form_index_parts[locals[:form_subject].id][:completed] %>
14
+ Complete
15
+ <% else %>
16
+ Incomplete
17
+ <% end %>
18
+ </div>
19
+ <% end %>
20
+ </div>
@@ -0,0 +1,2 @@
1
+ require "acts_as_multipart_form/railtie"
2
+ require "acts_as_multipart_form/engine"
@@ -0,0 +1,36 @@
1
+ # this file was stolen from kaminari
2
+ require 'active_support/configurable'
3
+
4
+ module ActsAsMultipartForm
5
+
6
+ # create new configs by passing a block with the config assignment
7
+ def self.configure(&block)
8
+ yield @config ||= ActsAsMultipartForm::Configuration.new
9
+ end
10
+
11
+ def self.config
12
+ @config
13
+ end
14
+
15
+ # setup config data
16
+ class Configuration
17
+ include ActiveSupport::Configurable
18
+ config_accessor :show_completed
19
+ config_accessor :show_incomplete_parts
20
+ config_accessor :use_numbered_parts_on_index
21
+ config_accessor :show_previous_next_links
22
+
23
+ def param_name
24
+ config.param_name.respond_to?(:call) ? config.param_name.call() : config.param_name
25
+ end
26
+ end
27
+
28
+ # setup default options
29
+ # this should match the generator config that goes in the initializer file
30
+ configure do |config|
31
+ config.show_completed = true
32
+ config.show_incomplete_parts = false
33
+ config.use_numbered_parts_on_index = true
34
+ config.show_previous_next_links = true
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module ActsAsMultipartForm
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,301 @@
1
+ module ActsAsMultipartForm
2
+
3
+ # Specify this to let the controller know how to setup the multipart forms.
4
+ # This sets up the form action, the form parts, and any other needed options.
5
+ # Each controller can have multiple multipart forms included on it
6
+ #
7
+ # The controller expects there to be an action for every form part for form_part_name and form_part_name_update
8
+ # There are currently no checks to verify these actions but an exception will be thrown when a missing
9
+ # action is called
10
+ module MultipartFormInController
11
+
12
+ def self.included(base)
13
+ base.extend ClassMethods
14
+ end
15
+
16
+ module ClassMethods
17
+ # Sets up the multipart form handler with the data needed to create and move through a multipart form
18
+ # The arguments takes several important values including:
19
+ # name: The name of the multipart form. This creates a controller action with that name that can be used in routes and other situations
20
+ # parts: An array of multipart form parts. Each part must have a corresponding part_name and part_name_update method
21
+ # model: The name of the model used to identify the multipart form. Defaults to the singularized name of the controller.
22
+ # form_route: The route for the form as specified in the config/routes file. Defaults to model_form_name downcased.
23
+ # show_route: The route the form redirects to once the last part is filled out. Defaults to the name of the model, downcased.
24
+ #
25
+ # The args parameter is an array of hashes and multiple multipart forms can be specified with a single acts_as_multipart_form call.
26
+ # To keep the lines from being too long, acts_as_multipart_form can be called multiple times to setup the forms
27
+ #
28
+ # sample set of multipart form actions
29
+ # def person_info
30
+ # @person = Person.find(params[:id])
31
+ # end
32
+ #
33
+ # def person_info_update
34
+ # @person = Person.find(params[:id])
35
+ # @person = Person.new if @person.nil?
36
+ #
37
+ # valid = @person.update_attributes(params[:person])
38
+ # return {:valid => valid, :errors => @person.errors}
39
+ # end
40
+ #
41
+ # def job_info
42
+ # @job_position = JobPosition.new
43
+ # @job_position.person = Person.find(load_multipart_form_data(form_instance_id, :person))
44
+ # end
45
+ #
46
+ # def job_info_update
47
+ # valid = @job_position.update_attributes(params[:job_position])
48
+ # return {:valid => valid, :errors => @job_position.errors}
49
+ # end
50
+ #
51
+ # @param [Array] args An array of hashes that determines the data for a multipart form
52
+ def acts_as_multipart_form(*args)
53
+
54
+ mattr_accessor :multipart_forms unless self.respond_to?(:multipart_forms)
55
+ self.multipart_forms = {} unless self.multipart_forms.is_a?(Hash)
56
+
57
+ forms = []
58
+ args.each do |arg|
59
+ # add the update parts
60
+ parts = arg[:parts]
61
+ arg[:parts] = []
62
+ parts.each do |part|
63
+ arg[:parts] << part
64
+ arg[:parts] << (part.to_s + "_update").to_sym
65
+ end
66
+ # sets default model if it is not set
67
+ arg[:model] = self.to_s.gsub("Controller", "").singularize unless arg.has_key?(:model)
68
+ arg[:form_route] = (arg[:model].downcase + "_" + arg[:name].to_s) unless arg.has_key?(:form_route)
69
+ arg[:show_route] = (arg[:model].downcase) unless arg.has_key?(:show_route)
70
+ # copy args to fields
71
+ self.multipart_forms[arg[:name]] = arg
72
+ forms << arg[:name]
73
+ end
74
+
75
+ before_filter :multipart_form_handler, :only => forms
76
+
77
+ include ActsAsMultipartForm::MultipartFormInController::InstanceMethods
78
+
79
+ end
80
+ end
81
+
82
+ module InstanceMethods
83
+
84
+ # A bad hack to load the multipart form information for the index page
85
+ # This must be called if you want to use the multipart_form/index_links partial
86
+ #
87
+ # Adds several instance variables available for the view
88
+ #
89
+ # @param [Symbol] form_name The name of the form
90
+ # @param [Array] form_subjects An array of active record objects that are form subjects for the given form
91
+ def load_multipart_form_index_links(form_name, form_subjects)
92
+ @multipart_form_index_parts = {}
93
+ form_subjects.each do |form_subject|
94
+ in_progress_form = find_or_create_multipart_in_progress_form(form_name, form_subject)
95
+ @multipart_form_index_parts[form_subject.id] = {}
96
+ @multipart_form_index_parts[form_subject.id][:parts] = get_available_multipart_form_parts(form_name, in_progress_form.last_completed_step)
97
+ @multipart_form_index_parts[form_subject.id][:completed] = in_progress_form.completed
98
+ end
99
+ @multipart_form_path = (self.multipart_forms[form_name][:form_route] + "_path").to_sym
100
+ end
101
+
102
+ # Handles multipart form setup on the controller
103
+ # Automatically called on the hire form action as a before filter
104
+ #
105
+ # It adds a bunch of instance variables to the controller so they are accessible to the view page.
106
+ # Not sure if this is the best way to do things
107
+ def multipart_form_handler
108
+ form_name = params[:action].to_sym
109
+ form_subject_id = params[:id]
110
+
111
+ form_subject = find_or_create_multipart_form_subject(form_name, form_subject_id)
112
+ params[:id] = form_subject.id
113
+
114
+ in_progress_form = find_or_create_multipart_in_progress_form(form_name, form_subject)
115
+
116
+ # set the part based on the params or in progress form
117
+ if params[:multipart_form_part]
118
+ part = params[:multipart_form_part].to_sym
119
+ elsif in_progress_form.last_completed_step != "none"
120
+ part = get_next_multipart_form_part(form_name, in_progress_form.last_completed_step.to_sym)
121
+ else
122
+ part = self.multipart_forms[form_name][:parts].first
123
+ end
124
+
125
+ # call and save the part information
126
+ if(part && self.multipart_forms[form_name][:parts].include?(part.to_sym))
127
+ result = self.send(part)
128
+
129
+ if(part.match(/_update$/))
130
+ if(result && result[:valid])
131
+ completed = redirect_to_next_multipart_form_part(form_name, form_subject, part)
132
+ in_progress_form.update_attributes(:last_completed_step => part, :completed => completed)
133
+ else
134
+ # render the previous page but stay on this page so we keep the errors
135
+ part = get_previous_multipart_form_part(form_name, part)
136
+ end
137
+ end
138
+ # get two previous parts so the previous link works
139
+ previous_part = get_previous_multipart_form_part(form_name, part)
140
+ @previous_multipart_form_part = get_previous_multipart_form_part(form_name, previous_part).to_s
141
+ # needs to be a string so that the view can read it
142
+ @multipart_form_part = part.to_s
143
+ @next_multipart_form_part = get_next_multipart_form_part(form_name, part).to_s
144
+ @form_subject = form_subject
145
+ @available_multipart_form_parts = get_available_multipart_form_parts(form_name, in_progress_form.last_completed_step)
146
+ @multipart_form_path = (self.multipart_forms[form_name][:form_route] + "_path").to_sym
147
+ @multipart_form_complete = in_progress_form.completed
148
+ end
149
+ end
150
+
151
+ # Determines if the symbol matches a multipart form name
152
+ #
153
+ # @param [Symbol] sym A name that may or may not correspond to a multipart form name
154
+ # @return [Boolean] Returns true if the symbol matches a multipart form name
155
+ def multipart_form_action?(sym)
156
+ self.multipart_forms.keys.include?(sym)
157
+ end
158
+
159
+ # Gets the next multipart form part for the form or returns the current part if it is first
160
+ #
161
+ # @param [Symbol] form The name of the multipart form
162
+ # @param [Symbol] part The name of the current part
163
+ # @returns [Symbol] The name of the next part
164
+ def get_previous_multipart_form_part(form, part)
165
+ part_index = self.multipart_forms[form][:parts].index(part)
166
+ if part_index > 0
167
+ return self.multipart_forms[form][:parts][part_index - 1]
168
+ else
169
+ return part
170
+ end
171
+ end
172
+
173
+ # Gets the previous multipart form part for the form or returns the current part if it is first
174
+ #
175
+ # @param [Symbol] form The name of the multipart form
176
+ # @param [Symbol] part The name of the current part
177
+ # @returns [Symbol] The name of the previous part
178
+ def get_next_multipart_form_part(form, part)
179
+ part_index = self.multipart_forms[form][:parts].index(part)
180
+ if part_index < self.multipart_forms[form][:parts].length - 1
181
+ return self.multipart_forms[form][:parts][part_index + 1]
182
+ else
183
+ return part
184
+ end
185
+ end
186
+
187
+ # Determines if the given multipart form part is the last part of the form
188
+ #
189
+ # @param [Symbol] form The name of the multipart form
190
+ # @param [Symbol] part The name o the current part
191
+ # @returns [Boolean] True if the given part matches the last part
192
+ def last_multipart_form_part?(form, part)
193
+ self.multipart_forms[form][:parts].last == part
194
+ end
195
+
196
+ # Determines if the given multipart form part is the first part of the form
197
+ #
198
+ # @param [Symbol] form The name of the multipart form
199
+ # @param [Symbol] part The name o the current part
200
+ # @returns [Boolean] True if the given part matches the first part
201
+ def first_multipart_form_part?(form, part)
202
+ self.multipart_forms[form][:parts].first == part
203
+ end
204
+
205
+
206
+ # Given a form name and a form subject id, it creates the form subject
207
+ # The form subject is defined by the id and the multipart form's model attribute
208
+ # The subject is created with values and saved without validations (this might change in the future)
209
+ #
210
+ # @param [Symbol] form_name The name of the multipart form
211
+ # @param [Integer] form_dubject_id The id of the form subject (could be nil)
212
+ # @return [FormSubject] The form subject object based on the multipart form's model or nil if the id is set and not found
213
+ def find_or_create_multipart_form_subject(form_name, form_subject_id)
214
+ # find or create the form subject
215
+ model = self.multipart_forms[form_name][:model]
216
+ if form_subject_id
217
+ form_subject = model.constantize.find(form_subject_id)
218
+ else
219
+ form_subject = model.constantize.new()
220
+ form_subject.save(:validate => false)
221
+ end
222
+ return form_subject
223
+ end
224
+
225
+ # Returns the InProgressForm object when given the form name and subject
226
+ # Creates the InPorgressForm object if it doesn't exist for the given form name/form subject pair
227
+ #
228
+ # @param [Symbol] form_name The name of the multipart form
229
+ # @param [FormSubject] form_subject The multipart form's subject
230
+ # @returns [InProgressForm] The associated or new in progress form object
231
+ def find_or_create_multipart_in_progress_form(form_name, form_subject)
232
+ # find or create the in progress form
233
+ # not sure why the polymorphic relationship isn't working here
234
+ in_progress_form = MultipartForm::InProgressForm.where(
235
+ :form_subject_id => form_subject.id,
236
+ :form_subject_type => form_subject.class.to_s,
237
+ :form_name => form_name).first
238
+ if !in_progress_form
239
+ in_progress_form = MultipartForm::InProgressForm.create(
240
+ :form_subject_id => form_subject.id,
241
+ :form_subject_type => form_subject.class.to_s,
242
+ :form_name => form_name,
243
+ :last_completed_step => "none",
244
+ :completed => false)
245
+ end
246
+ return in_progress_form
247
+ end
248
+
249
+ # Adds a redirect based on the information passed in.
250
+ # If on the last part of the form, tries to redirect to the view page,
251
+ # otherwise to the next form part.
252
+ #
253
+ # This method needs signficantly more testing (7-20-2011)
254
+ #
255
+ # @param [Sybmol] form_name The name of the form
256
+ # @param [FormSubject] form_subject The subject of the form
257
+ # @param [Symbol] part The current form part
258
+ def redirect_to_next_multipart_form_part(form_name, form_subject, part)
259
+ # set highest completed part to the current part4
260
+ if(last_multipart_form_part?(form_name, part))
261
+ # render the view page(not sure how to do this)
262
+ redirect_to( send(self.multipart_forms[form_name][:show_route] + "_path", form_subject) )
263
+ completed = true
264
+ else
265
+ # render the next page
266
+ next_part = get_next_multipart_form_part(form_name, part)
267
+ # maybe pass in a route
268
+ redirect_to ( send(
269
+ self.multipart_forms[form_name][:form_route] + "_path",
270
+ :id => form_subject.id.to_s,
271
+ :multipart_form_part => next_part.to_s))
272
+ completed = false
273
+ end
274
+ return completed
275
+ end
276
+
277
+ # Gets the multipart form parts the user is allowed to directly link to
278
+ # with respect to the config information.
279
+ #
280
+ # If the config option show_incomplete_parts is set to false, do not return parts past the in_progress_form's last completed step
281
+ #
282
+ # @param [Symbol] form_name The name of the form
283
+ # @returns [Array] An array of form part symbols with no _update parts and other config restrictions
284
+ def get_available_multipart_form_parts(form_name, last_completed_part)
285
+ add_parts = true
286
+ parts = []
287
+ # loop over the parts
288
+ self.multipart_forms[form_name][:parts].each do |part|
289
+ if( add_parts && !part.match(/_update$/) )
290
+ parts << { :name => part, :number => parts.length + 1 }
291
+ end
292
+ if !ActsAsMultipartForm.config.show_incomplete_parts && part.to_s == last_completed_part.to_s
293
+ add_parts = false
294
+ end
295
+ end
296
+ return parts
297
+ end
298
+
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,105 @@
1
+ module ActsAsMultipartForm
2
+ # Specify this to let the model know to expect multipart_form controller actions
3
+ # Allows the model to run conditional validations by giving access to methods
4
+ # with the form: multipart_form_name_multipart_controller_action.
5
+ #
6
+ # It includes support for multiple forms on a single controller by passing in an array of
7
+ # form symbols or a single symbol.
8
+ module MultipartFormInModel
9
+
10
+ def self.included(base)
11
+ base.extend ClassMethods
12
+ end
13
+
14
+ module ClassMethods
15
+ # Adds the information to the model needed to do conditional validations on the multipart forms
16
+ # Creates the multipart_forms field to store the list of forms the model has access to
17
+ # Creates the multipart_form_controller_action field to store the form the controller is currently on
18
+ # This is used for validations among other things
19
+ #
20
+ # @param [Hash] options A hash of symbols that represent multipart forms in the controller
21
+ def multipart_formable(*args)
22
+
23
+ mattr_accessor :multipart_form_controller_action unless self.respond_to?(:multipart_form_controller_action)
24
+ mattr_accessor :multipart_forms unless self.respond_to?(:multipart_forms)
25
+ self.multipart_forms = [] unless self.multipart_forms.is_a?(Array)
26
+ self.multipart_forms |= args[0][:forms]
27
+
28
+ # after save, the current controller action should not be set
29
+ after_save :reset_multipart_form_controller_action
30
+
31
+ include ActsAsMultipartForm::MultipartFormInModel::InstanceMethods
32
+ end
33
+ end
34
+
35
+ module InstanceMethods
36
+
37
+ # Sets the controller action to nil
38
+ # When we are not performing a save (or other action from a controller),
39
+ # the controller action should not be set
40
+ def reset_multipart_form_controller_action
41
+ self.multipart_form_controller_action = nil
42
+ end
43
+
44
+ # Determines whether multipart form controller is in use
45
+ # @returns [Boolean] True if both the multipart_forms and multipart_form_controller fields are set
46
+ def using_multipart_forms?
47
+ return(!self.multipart_forms.nil? && !self.multipart_form_controller_action.nil?)
48
+ end
49
+
50
+ # Overrides method missing to return true if the method is of the form
51
+ # multipart_form_name_multipart_controller_action
52
+ #
53
+ # If those conditions are not satisfied, called super
54
+ #
55
+ # @param [Symbol] sym The name of the method
56
+ # @param [Array[ args The arguments of the method
57
+ # @returns [Boolean] Whether or not the argument corresponds to a multipart form, otherwise super
58
+ def method_missing(sym, *args)
59
+ if multipart_form_method?(sym)
60
+ return multipart_form_controller_action?(sym)
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ # Overrides respond to to return true if the method is of the form
67
+ # multipart_form_name_multipart_controller_action
68
+ #
69
+ # If those conditions are not satisfied, called super
70
+ #
71
+ # @param [Symbol] sym The name of the method
72
+ # @param [Array[ args The arguments of the method
73
+ # @returns [Boolean] Whether or not the argument corresponds to a multipart form, otherwise super
74
+ def respond_to?(sym, *args)
75
+ if multipart_form_method?(sym)
76
+ return multipart_form_controller_action?(sym)
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+ # determines whether the given method should be handled by the multipart form method handler
83
+ # based on whether it starts with the form name followed by an underscore
84
+ #
85
+ # @param [Symbol] sym Method to check
86
+ # @return [Boolean] Whether or not the symbol starts with one of the multipart forms
87
+ def multipart_form_method?(sym)
88
+ if self.multipart_forms
89
+ return self.multipart_forms.select {|form| sym.to_s =~ /^#{form}_/}.length > 0
90
+ end
91
+ return false
92
+ end
93
+
94
+ # Determines if the symbol corresponds to a multipart form action
95
+ # @param [Symbol] sym The name of the method
96
+ # @returns [Boolean] Whether or not the argument corresponds to a multipart form, otherwise super
97
+ def multipart_form_controller_action?(sym)
98
+ if using_multipart_forms?
99
+ return self.multipart_forms.select {|form| form.to_s + "_" + self.multipart_form_controller_action + "?" == sym.to_s}.length > 0
100
+ end
101
+ return false
102
+ end
103
+ end
104
+ end
105
+ end