dry_crud 1.2.7 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README.rdoc +60 -27
  2. data/Rakefile +3 -1
  3. data/VERSION +1 -1
  4. data/lib/generators/dry_crud/dry_crud_generator.rb +3 -3
  5. data/lib/generators/dry_crud/templates/INSTALL +3 -1
  6. data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +106 -90
  7. data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +90 -74
  8. data/lib/generators/dry_crud/templates/app/controllers/render_inheritable.rb +34 -33
  9. data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +39 -23
  10. data/lib/generators/dry_crud/templates/app/helpers/list_helper.rb +11 -9
  11. data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +55 -47
  12. data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +134 -86
  13. data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +41 -35
  14. data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.erb +1 -0
  15. data/lib/generators/dry_crud/templates/app/views/crud/edit.html.erb +3 -3
  16. data/lib/generators/dry_crud/templates/app/views/crud/new.html.erb +2 -2
  17. data/lib/generators/dry_crud/templates/app/views/crud/show.html.erb +3 -3
  18. data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +9 -7
  19. data/lib/generators/dry_crud/templates/app/views/list/_search.html.erb +1 -1
  20. data/lib/generators/dry_crud/templates/app/views/list/index.html.erb +4 -4
  21. data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +3 -1
  22. data/lib/generators/dry_crud/templates/config/locales/en_crud.yml +63 -0
  23. data/lib/generators/dry_crud/templates/test/crud_test_model.rb +93 -58
  24. data/lib/generators/dry_crud/templates/test/custom_assertions.rb +24 -13
  25. data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +26 -56
  26. data/lib/generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +47 -41
  27. data/lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb +28 -24
  28. data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +20 -34
  29. data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +39 -53
  30. data/lib/generators/dry_crud/templates/test/unit/helpers/render_inheritable_test.rb +33 -33
  31. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb +27 -27
  32. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +103 -50
  33. data/lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb +52 -24
  34. data/test/templates/Gemfile +34 -0
  35. data/test/templates/app/controllers/ajax_controller.rb +3 -3
  36. data/test/templates/app/controllers/application_controller.rb +1 -1
  37. data/test/templates/app/controllers/cities_controller.rb +2 -5
  38. data/test/templates/app/controllers/people_controller.rb +5 -5
  39. data/test/templates/app/controllers/vips_controller.rb +6 -11
  40. data/test/templates/app/helpers/people_helper.rb +2 -2
  41. data/test/templates/app/models/city.rb +9 -9
  42. data/test/templates/app/models/person.rb +5 -4
  43. data/test/templates/app/views/ajax/_actions_index.html.erb +2 -2
  44. data/test/templates/app/views/cities/_form.html.erb +5 -1
  45. data/test/templates/app/views/layouts/_menu.html.erb +3 -3
  46. data/test/templates/app/views/people/_attrs.html.erb +3 -3
  47. data/test/templates/config/database.yml +22 -0
  48. data/test/templates/config/locales/en_cities.yml +56 -0
  49. data/test/templates/config/routes.rb +5 -5
  50. data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +5 -2
  51. data/test/templates/db/seeds.rb +38 -29
  52. data/test/templates/test/functional/cities_controller_test.rb +12 -12
  53. data/test/templates/test/functional/people_controller_test.rb +10 -10
  54. metadata +11 -7
data/README.rdoc CHANGED
@@ -18,9 +18,9 @@ To integrate DRY CRUD into your code, only a few additions are required:
18
18
 
19
19
  * For uniform CRUD functionality, just subclass your controllers from +CrudController+.
20
20
  * To use standard formatting, tables and forms throughout your application, add <tt>helper :standard</tt> to your +ApplicationController+ and benefit everywhere from these little helper methods.
21
- * Add a <tt>:label</tt> method to your models for a human-friendly representation.
21
+ * Overwrite the <tt>:to_s</tt> method of your models for a human-friendly representation.
22
22
 
23
- Version 1.0.0 and higher are built for Rails 3. If you need a version for Rails 2.3, please get version 0.6.0 of the gem or go to the rails-2.3 branch on Github.
23
+ Version 1.0 and higher are built for Rails 3. If you need a version for Rails 2.3, please get version 0.6.0 of the gem or go to the rails-2.3 branch on Github. DRY CRUD 1.3 is fully compatible with Ruby 1.8.7, Ruby 1.9.2 and JRuby.
24
24
 
25
25
  == Overview
26
26
 
@@ -44,7 +44,7 @@ See the Examples section for some use cases and the Generated Files section belo
44
44
 
45
45
  === Controller with CRUD functionality
46
46
 
47
- Say you want to manage a +Person+ model. Create the following controller and add a <tt>:label</tt> method to your model for a human-friendly representation used in page titles.
47
+ Say you want to manage a +Person+ model. Create the following controller and overwrite the <tt>:to_s</tt> method of your model for a human-friendly representation used in page titles.
48
48
 
49
49
  <tt>app/controllers/people_controller.rb</tt>:
50
50
  class PeopleController < CrudController
@@ -52,7 +52,7 @@ Say you want to manage a +Person+ model. Create the following controller and add
52
52
 
53
53
  <tt>app/models/person.rb</tt>:
54
54
  class Person
55
- def label
55
+ def to_s
56
56
  "#{lastname} #{firstname}"
57
57
  end
58
58
  end
@@ -64,7 +64,7 @@ That's it. You have a sortable overview of all people, detail pages and forms to
64
64
 
65
65
  Well, maybe there are certain attributes you do not want to display in the people list, or others that are not editable. No problem, simply create a <tt> _list</tt> partial in <tt>app/views/people/_list.html.erb</tt> to customize this:
66
66
 
67
- <%= crud_table [:lastname, :firstname, :city, :sex] %>
67
+ <%= crud_table :lastname, :firstname, :city, :sex %>
68
68
 
69
69
  This only displays these three attributes in the table. All other templates, as well as the main index view, fallback to the ones in <tt>app/views/crud</tt>.
70
70
 
@@ -87,18 +87,20 @@ And we are done again. All our controllers inheriting from +ListController+, inc
87
87
  If the current page should be remembered while viewing or editing an entry, just add :page to the remembered_params in <tt>ListController::Memory</tt>:
88
88
 
89
89
  controller.remember_params = [:q, :sort, :sort_dir, :page]
90
+
91
+ In this case, you should also pass the parameter <tt>page=1</tt> with a hidden field in your <tt>list/_search.html.erb</tt> to start displaying search results at page one.
90
92
 
91
93
 
92
94
  ==== Special formatting for selected attributes
93
95
 
94
- Sometimes, the default formatting provided by +:format_attr+ will not be sufficient. We have a boolean column <tt>sex</tt> in our model, but would like to display 'male' or 'female' for it (instead of 'no' or 'yes', which is a bit cryptic). Just define a method in your view helper starting with <tt>format_</tt>, followed by the attribute name:
96
+ Sometimes, the default formatting provided by <tt>:format_attr</tt> will not be sufficient. We have a boolean column +sex+ in our model, but would like to display 'male' or 'female' for it (instead of 'no' or 'yes', which is a bit cryptic). Just define a method in your view helper starting with <tt>format_</tt>, followed by the attribute name:
95
97
 
96
98
  In <tt>app/helpers/people.rb</tt>:
97
99
  def format_sex(person)
98
100
  person.sex ? 'female' : 'male'
99
101
  end
100
102
 
101
- By the way: The method +:f+ in +StandardHelper+ uniformly formats arbitrary values according to their class.
103
+ By the way: The method <tt>:f</tt> in +StandardHelper+ uniformly formats arbitrary values according to their class.
102
104
 
103
105
 
104
106
  ==== Filtering the index list
@@ -164,10 +166,10 @@ To render custom columns, use the :col method:
164
166
 
165
167
  Forms work very similar. In the most simple case, you just have to specify which attributes of a model to create input fields for, and you get a complete form with error messages, labeled input fields according the column types and a save button:
166
168
 
167
- <%= standard_form(@person, [:firstname, :lastname, :age, :city] -%>
169
+ <%= standard_form(@person, :firstname, :lastname, :age, :city) -%>
168
170
 
169
171
  Of course, custom input fields may be defined as well:
170
- <%= standard_form(@person, [], :url => {:action => 'custom_update', :id => @person.id}) do |f| %>
172
+ <%= standard_form(@person, :url => custom_update_person_path(@person.id)) do |f| %>
171
173
  <%= f.labeled_input_fields :firstname, :lastname %>
172
174
  <%= f.labeled(:sex) do %>
173
175
  <%= f.radio_button :sex, true %> female
@@ -182,13 +184,35 @@ Even +belongs_to+ associations are automatically rendered with a select field. B
182
184
 
183
185
  Yes, it's bad practice to use finder logic in your views! Define the variable <tt>@hometowns</tt> in your controller instead (as shown in the example above), and you do not even have to specify the <tt>:list</tt> option.
184
186
 
187
+ === Internationalization (I18N)
188
+
189
+ All text strings used are externalized to an english locale yaml. The keys are organized by controller and template name plus a generic global scope.
190
+
191
+ To represent the controller hierarchy used by <tt>render_inheritable</tt>, a special translation helper <tt>:ti</tt> looks up keys along this hierarchy in the following order:
192
+ {controller_name}.{template_name}.{key}
193
+ {controller_name}.{action_name}.{key}
194
+ {controller_name}.global.{key}
195
+ {parent_controller_name}.{template_name}.{key}
196
+ {parent_controller_name}.{action_name}.{key}
197
+ {parent_controller_name}.global.{key}
198
+ ...
199
+ global.{key}
200
+
201
+ In order to change the title for your +PeopleController+'s +index+ action, you do not need to override the entire template, but simply define the following key:
202
+ people.index.title = "The People"
203
+
204
+ Otherwise, the lookup for the title would fallback on the +ListController+'s key <tt>list.index.title</tt>.
205
+
206
+ This lookup mechanism also allows you to easily define per-controller overridable text snippets in your views.
207
+
208
+
185
209
  == Generated Files
186
210
 
187
211
  All generated files are supposed to provide a reasonable foundation for the CRUD functionality. You are encouraged to adapt them to fit the needs of your application. They're yours!
188
212
 
189
213
  === Controller:
190
214
 
191
- {controller/crud_controller.rb}[http://codez.ch/dry_crud/?q=CrudController]:: Abstract controller providing basic CRUD actions. This implementation mainly follows the one of the Rails scaffolding controller and responses to HTML and XML requests. Some enhancements were made to ease extendability. Several protected helper methods are there to be (optionally) overriden by subclasses. With the help of additional callbacks, it is possible to hook into the action procedures without overriding the entire method. This class is based on ListController.
215
+ {controller/crud_controller.rb}[http://codez.ch/dry_crud/?q=CrudController]:: Abstract controller providing basic CRUD actions. This implementation mainly follows the one of the Rails scaffolding controller and responses to HTML and XML requests. Some enhancements were made to ease extendability. Several protected helper methods are there to be (optionally) overriden by subclasses. With the help of additional callbacks, it is possible to hook into the action procedures without overriding the entire method. This class is based on +ListController+.
192
216
 
193
217
  {controller/list_controller.rb}[http://codez.ch/dry_crud/?q=ListController]:: Abstract controller providing a basic list action. There are two sub-modules that provide search and sort functionality for the table displayed in the list action. A third sub-module remembers the list parameters in order to return to an identical list.
194
218
 
@@ -197,33 +221,44 @@ All generated files are supposed to provide a reasonable foundation for the CRUD
197
221
 
198
222
  === Helpers:
199
223
 
200
- {helpers/standard_helper.rb}[http://codez.ch/dry_crud/?q=StandardHelper]:: A view helper to standardize often used functions like formatting, tables, forms or action links. This helper is ideally defined in the ApplicationController. It is required to use the StandardTableBuilder and the StandardFormBuilder.
224
+ {helpers/standard_helper.rb}[http://codez.ch/dry_crud/?q=StandardHelper]:: A view helper to standardize often used functions like formatting, tables, forms or action links. This helper is ideally defined in the +ApplicationController+. It is required to use the +StandardTableBuilder+ and the +StandardFormBuilder+.
201
225
 
202
- {helpers/crud_helper.rb}[http://codez.ch/dry_crud/?q=CrudHelper]:: A small helper for CrudController to render tables and forms with a default set of attributes.
226
+ {helpers/crud_helper.rb}[http://codez.ch/dry_crud/?q=CrudHelper]:: A small helper for +CrudController+ to render tables and forms with a default set of attributes.
203
227
 
204
- {helpers/list_helper.rb}[http://codez.ch/dry_crud/?q=ListHelper]:: A small helper for ListController to render the list table with a default set of attributes.
228
+ {helpers/list_helper.rb}[http://codez.ch/dry_crud/?q=ListHelper]:: A small helper for +ListController+ to render the list table with a default set of attributes.
205
229
 
206
230
  {helpers/standard_table_builder.rb}[http://codez.ch/dry_crud/?q=StandardTableBuilder]:: A simple helper object to easily define tables listing several rows of the same data type.
207
231
 
208
- {helpers/standard_form_builder.rb}[http://codez.ch/dry_crud/?q=StandardFormBuilder]:: A form builder that automatically selects the corresponding input element for ActiveRecord columns. Input elements are rendered with a corresponding label by default.
232
+ {helpers/standard_form_builder.rb}[http://codez.ch/dry_crud/?q=StandardFormBuilder]:: A form builder that automatically selects the corresponding input type for ActiveRecord columns. Input elements are rendered together with a label by default.
209
233
 
210
234
 
211
235
  === Views:
212
236
 
213
- All templates in the +crud+ folder may be 'overriden' individually in a respective view folder. Define the basic structure of your CRUD views here and adapt it as required for each single model.
237
+ All templates in the +list+ and +crud+ folders may be 'overriden' individually in a respective view folder. Define the basic structure of your CRUD views here and adapt it as required for each single model. Actually, the <tt>_list.html.erb</tt> partial from the +list+ folder gets overriden in the +crud+ folder already.
238
+
239
+ ==== List
240
+
241
+ views/list/index.html.erb:: The index view displaying a sortable table with all entries. If you have +search_columns+ defined for your controller, then a search box is rendered as well.
242
+
243
+ views/list/_list.html.erb:: A partial defining the table in the index view. To change the displayed attributes for your list model, just create an own <tt>_list.html.erb</tt> in your controller's view directory.
214
244
 
245
+ views/list/_search.html.erb:: A partial defining a simple search form that is displayed when +search_columns+ are defined in a subclassing controller.
246
+
247
+ views/list/_actions_index.html.erb:: The action links available in the index view. None by default.
248
+
249
+ ==== Crud
215
250
 
216
251
  views/crud/show.html.erb:: The show view displaying all the attributes of one entry and the various actions to perform on it.
217
252
 
218
253
  views/crud/_attrs.html.erb:: A partial defining the attributes to be displayed in the show view.
219
254
 
220
- views/crud/_list.html.erb:: A partial defining the table in the index view. To change the displayed attributes for your list model, just create an own _list.html.erb in your controller's view directory.
255
+ views/crud/_list.html.erb:: A partial defining the table in the index view with various links to manipulate the entries.
221
256
 
222
257
  views/crud/new.html.erb:: The view to create a new entry.
223
258
 
224
259
  views/crud/edit.html.erb:: The view to edit an existing entry.
225
260
 
226
- views/crud/_form.html.erb:: The form used to create and edit entries. If you would like to customize this form for various models, just create an own _form.html.erb in your controller's view directory.
261
+ views/crud/_form.html.erb:: The form used to create and edit entries. If you would like to customize this form for various models, just create an own <tt>_form.html.erb</tt> in your controller's view directory.
227
262
 
228
263
  views/crud/_actions_index.html.erb:: The action links available in the index view.
229
264
 
@@ -231,22 +266,20 @@ views/crud/_actions_show.html.erb:: The action links available in the show view.
231
266
 
232
267
  views/crud/_actions_edit.html.erb:: The action links available in the edit view.
233
268
 
234
- views/list/index.html.erb:: The index view displaying a sortable table with all entries. If you have +search_columns+ defined for your controller, then a search box is rendered as well.
235
-
236
- views/list/_list.html.erb:: A partial defining the table in the index view. To change the displayed attributes for your list model, just create an own _list.html.erb in your controller's view directory.
237
-
238
- views/list/_search.html.erb:: A partial defining a simple search form that is displayed when +search_columns+ are defined in a subclassing controller.
239
-
240
- views/list/_actions_index.html.erb:: The action links available in the index view. None by default.
269
+ ==== Various
241
270
 
242
271
  views/shared/_labeled.html.erb:: Partial to define the layout for an arbitrary content with a label.
243
272
 
244
- views/layouts/crud.html.erb:: An example layout showing how to use the @title and +flash+. Most probably you want to merge this with your application.html.erb or adapt the main CRUD templates, so you wont need this file.
273
+ views/shared/_error_messages.html.erb:: Partial to display the validation errors in Rails 2 style.
274
+
275
+ views/layouts/crud.html.erb:: An example layout showing how to use the <tt>@title</tt> and +flash+. Most probably you want to merge this with your <tt>application.html.erb</tt> or adapt the main CRUD templates, so you wont need this file.
245
276
 
246
- views/layouts/_menu.html.erb:: An empty file to put your menu items into. Included from +list.html.erb+.
277
+ views/layouts/_menu.html.erb:: An empty file to put your menu items into. Included from <tt>crud.html.erb</tt>.
247
278
 
248
279
  public/stylesheets/crud.css:: A simple CSS with all the classes and ids used in the CRUD code.
249
280
 
281
+ public/images/action/*.png:: Some sample action icons from the {Open Icon Library}[http://openiconlibrary.sourceforge.net].
282
+
250
283
 
251
284
  === Tests:
252
285
 
@@ -254,7 +287,7 @@ public/stylesheets/crud.css:: A simple CSS with all the classes and ids used in
254
287
 
255
288
  {test/custom_assertions.rb}[http://codez.ch/dry_crud/?q=CustomAssertions]:: A handful of convenient assertions. Include this module into your <tt>test_helper.rb</tt> file.
256
289
 
257
- {test/functionals/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/?q=CrudControllerTestHelper]:: A module to include into the functional tests for your CrudController subclasses. Contains a handful of CRUD functionality tests for the provided implementation. So for each new CRUD controller, you get 20 tests for free.
290
+ {test/functionals/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/?q=CrudControllerTestHelper]:: A module to include into the functional tests for your +CrudController+ subclasses. Contains a handful of CRUD functionality tests for the provided implementation. So for each new CRUD controller, you get 20 tests for free.
258
291
 
259
292
  test/several other tests:: Testing the provided implementation and a great base to test your adaptions of the CRUD code.
260
293
 
data/Rakefile CHANGED
@@ -48,6 +48,7 @@ namespace :test do
48
48
  task :create do
49
49
  unless File.exist?(TEST_APP_ROOT)
50
50
  sh "rails new #{TEST_APP_ROOT}"
51
+ FileUtils.cp(File.join(File.dirname(__FILE__), 'test', 'templates', 'Gemfile'), TEST_APP_ROOT)
51
52
  end
52
53
  end
53
54
 
@@ -66,7 +67,8 @@ namespace :test do
66
67
  File.join(TEST_APP_ROOT, 'app', 'views', 'layouts', 'application.html.erb'),
67
68
  :force => true)
68
69
  FileUtils.cd(TEST_APP_ROOT) do
69
- sh "rake db:migrate db:seed db:test:prepare RAILS_ENV=development"
70
+ sh "rake db:migrate db:seed RAILS_ENV=development"
71
+ sh "rake db:migrate RAILS_ENV=test" # db:test:prepare does not work for jdbcsqlite3
70
72
  end
71
73
  end
72
74
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.7
1
+ 1.3.0
@@ -1,11 +1,11 @@
1
1
  require 'rails/generators'
2
2
 
3
3
  class DryCrudGenerator < Rails::Generators::Base
4
-
4
+
5
5
  def self.source_root
6
6
  File.join(File.dirname(__FILE__), 'templates')
7
7
  end
8
-
8
+
9
9
  def install_dry_crud
10
10
  # copy everything in template subfolders
11
11
  Dir.chdir(self.class.source_root) do
@@ -13,7 +13,7 @@ class DryCrudGenerator < Rails::Generators::Base
13
13
  directory(f) if File.directory?(f)
14
14
  end
15
15
  end
16
-
16
+
17
17
  readme "INSTALL"
18
18
  end
19
19
 
@@ -8,6 +8,8 @@ required:
8
8
  * To use standard formatting, tables and forms throughout your
9
9
  application, add 'helper :standard' to your ApplicationController and
10
10
  benefit everywhere from these little helper methods.
11
- * Add a #label method to your models for a human-friendly representation.
11
+ * Overwrite the :to_s method of your models for a human-friendly
12
+ representation.
13
+
12
14
 
13
15
  Enjoy dry_crud and stay DRY!
@@ -5,47 +5,37 @@
5
5
  # With the help of additional callbacks, it is possible to hook into the action procedures without
6
6
  # overriding the entire method.
7
7
  class CrudController < ListController
8
-
8
+
9
+ include ERB::Util
10
+
9
11
  # Set up entry object to use in the various actions.
10
12
  before_filter :build_entry, :only => [:new, :create]
11
13
  before_filter :set_entry, :only => [:show, :edit, :update, :destroy]
12
-
14
+
13
15
  helper_method :full_entry_label
14
-
15
- delegate :model_identifier, :to => 'self.class'
16
-
16
+
17
+ delegate :model_identifier, :to => 'self.class'
18
+
17
19
  hide_action :model_identifier, :run_callbacks
18
-
19
-
20
- # Defines before and after callback hooks for create, update, save and destroy.
20
+
21
+
22
+ # Defines before and after callback hooks for create, update, save and destroy actions.
21
23
  define_model_callbacks :create, :update, :save, :destroy
22
-
24
+
23
25
  # Defines before callbacks for the render actions. A virtual callback
24
26
  # unifiying render_new and render_edit, called render_form, is defined further down.
25
- define_model_callbacks :render_show,
26
- :render_new,
27
- :render_edit,
28
- :only => :before,
29
- :terminator => "result == false || performed?"
30
-
31
- # Verify that required :id param is present and only allow good http methods.
32
- # Uncomment if you have the Rails verification plugin installed.
33
- #verify :params => :id, :only => :show, :redirect_to => { :action => 'index' }
34
- #verify :method => :post, :only => :create, :redirect_to => { :action => 'index' }
35
- #verify :method => [:put, :post], :params => :id, :only => :update, :redirect_to => { :action => 'index' }
36
- #verify :method => [:delete, :post], :params => :id, :only => :destroy, :redirect_to => { :action => 'index' }
37
-
38
-
27
+ define_render_callbacks :show, :new, :edit
28
+
29
+
39
30
  ############## ACTIONS ############################################
40
31
 
41
-
42
32
  # Show one entry of this model.
43
33
  # GET /entries/1
44
34
  # GET /entries/1.xml
45
35
  def show
46
36
  respond_with @entry
47
37
  end
48
-
38
+
49
39
  # Display a form to create a new entry of this model.
50
40
  # GET /entries/new
51
41
  # GET /entries/new.xml
@@ -55,112 +45,138 @@ class CrudController < ListController
55
45
  end
56
46
 
57
47
  # Create a new entry of this model from the passed params.
48
+ # There are before and after create callbacks to hook into the action.
49
+ # To customize the response, you may overwrite this action and call
50
+ # super with a block that gets success and format parameters.
58
51
  # POST /entries
59
52
  # POST /entries.xml
60
- def create
53
+ def create(&block)
61
54
  @entry.attributes = params[model_identifier]
62
- created = with_callbacks(:create) { save_entry }
63
-
64
- respond_processed(created, 'created', 'new') do |format|
65
- format.xml { render :xml => @entry, :status => :created, :location => @entry } if created
55
+ created = with_callbacks(:create, :save) { @entry.save }
56
+
57
+ customizable_respond_to(created, block) do |format|
58
+ if created
59
+ format.html { redirect_to_show success_notice }
60
+ format.xml { render :xml => @entry, :status => :created, :location => @entry }
61
+ else
62
+ format.html { render_with_callback 'new' }
63
+ format.xml { render :xml => @entry.errors, :status => :unprocessable_entity }
64
+ end
66
65
  end
67
66
  end
68
-
67
+
69
68
  # Display a form to edit an exisiting entry of this model.
70
69
  # GET /entries/1/edit
71
70
  def edit
72
71
  render_with_callback 'edit'
73
72
  end
74
-
73
+
75
74
  # Update an existing entry of this model from the passed params.
75
+ # There are before and after update callbacks to hook into the action.
76
+ # To customize the response, you may overwrite this action and call
77
+ # super with a block that gets success and format parameters.
76
78
  # PUT /entries/1
77
79
  # PUT /entries/1.xml
78
- def update
80
+ def update(&block)
79
81
  @entry.attributes = params[model_identifier]
80
- updated = with_callbacks(:update) { save_entry }
81
-
82
- respond_processed(updated, 'updated', 'edit')
82
+ updated = with_callbacks(:update, :save) { @entry.save }
83
+
84
+ customizable_respond_to(updated, block) do |format|
85
+ if updated
86
+ format.html { redirect_to_show success_notice }
87
+ format.xml { head :ok }
88
+ else
89
+ format.html { render_with_callback 'edit' }
90
+ format.xml { render :xml => @entry.errors, :status => :unprocessable_entity }
91
+ end
92
+ end
83
93
  end
84
-
94
+
85
95
  # Destroy an existing entry of this model.
96
+ # There are before and after destroy callbacks to hook into the action.
97
+ # To customize the response, you may overwrite this action and call
98
+ # super with a block that gets success and format parameters.
86
99
  # DELETE /entries/1
87
100
  # DELETE /entries/1.xml
88
- def destroy
89
- destroyed = with_callbacks(:destroy) { @entry.destroy }
90
-
91
- respond_processed(destroyed, 'destroyed') do |format|
92
- format.html do
93
- if destroyed
94
- redirect_to_index
95
- else
96
- flash.alert = @entry.errors.full_messages.join('<br/>').html_safe
97
- request.env["HTTP_REFERER"].present? ? redirect_to(:back) : redirect_to_show
98
- end
99
- end
100
- end
101
- end
102
-
103
- protected
104
-
105
- ############# CUSTOMIZABLE HELPER METHODS ##############################
106
-
107
- # Convenience method to respond to various formats if the performed
108
- # action may succeed or fail. It is possible to pass a block and respond
109
- # in custom ways for certain cases. If no response is performed in the
110
- # given block, the default responses in this method are executed.
111
- def respond_processed(success, operation, failed_action = 'show')
112
- respond_to do |format|
113
- flash.notice = "#{full_entry_label} was successfully #{operation}." if success
114
- yield format if block_given?
115
- return if performed?
116
-
117
- # fallback responders if nothing was performed in the block
118
- if success
119
- format.html { redirect_to_show }
101
+ def destroy(&block)
102
+ destroyed = run_callbacks(:destroy) { @entry.destroy }
103
+
104
+ customizable_respond_to(destroyed, block) do |format|
105
+ if destroyed
106
+ format.html { redirect_to_index success_notice }
120
107
  format.xml { head :ok }
121
- else
122
- format.html { render_with_callback failed_action }
108
+ else
109
+ format.html {
110
+ flash.alert = @entry.errors.full_messages.join('<br/>')
111
+ request.env["HTTP_REFERER"].present? ? redirect_to(:back) : redirect_to_show
112
+ }
123
113
  format.xml { render :xml => @entry.errors, :status => :unprocessable_entity }
124
114
  end
125
115
  end
126
116
  end
127
-
117
+
118
+ protected
119
+
120
+ ############# CUSTOMIZABLE HELPER METHODS ##############################
121
+
128
122
  # Creates a new model entry.
129
123
  def build_entry
130
124
  @entry = model_class.new
131
125
  end
132
-
126
+
133
127
  # Sets an existing model entry from the given id.
134
128
  def set_entry
135
129
  @entry = model_class.find(params[:id])
136
130
  end
137
-
131
+
138
132
  # A label for the current entry, including the model name.
139
133
  def full_entry_label
140
- "#{models_label.singularize} '#{@entry.label}'"
134
+ "#{models_label(false)} <i>#{h(@entry)}</i>".html_safe
141
135
  end
142
-
136
+
143
137
  # Redirects to the show action of a single entry.
144
- def redirect_to_show
145
- redirect_to @entry
138
+ def redirect_to_show(options = {})
139
+ redirect_to @entry, options
146
140
  end
147
-
141
+
148
142
  # Redirects to the main action of this controller.
149
- def redirect_to_index
150
- redirect_to polymorphic_path(model_class, :returning => true)
143
+ def redirect_to_index(options = {})
144
+ redirect_to polymorphic_path(model_class, :returning => true), options
151
145
  end
152
-
153
- # Saves the current entry with callbacks.
154
- def save_entry
155
- with_callbacks(:save) { @entry.save }
146
+
147
+ # Helper method the run the given block in between the before and after
148
+ # callbacks of the given kinds.
149
+ def with_callbacks(*kinds, &block)
150
+ kinds.reverse.inject(block) do |b, kind|
151
+ lambda { run_callbacks(kind, &b) }
152
+ end.call
156
153
  end
157
154
 
158
- # Helper method the run the given block in between the before and after
159
- # callbacks of the given kind.
160
- def with_callbacks(kind, &block)
161
- send(:"_run_#{kind}_callbacks", &block)
155
+ private
156
+
157
+ # Convenience method to respond to various formats if the performed
158
+ # action may succeed or fail. It is possible to pass a custom_block and respond
159
+ # in custom ways for certain cases. If no response is performed in the
160
+ # given block, the default responses in the main block are executed.
161
+ def customizable_respond_to(success, custom_block = nil)
162
+ respond_to do |format|
163
+ custom_block.call(success, format) if custom_block
164
+ return if performed?
165
+
166
+ yield format
167
+ end
162
168
  end
163
169
 
170
+ # Create an I18n flash notice if the action was successfull.
171
+ # Uses the key {controller_name}.{action_name}.flash.success
172
+ # or crud.{action_name}.flash.success as fallback.
173
+ def success_notice
174
+ key = "#{action_name}.flash.success"
175
+ {:notice => t(:"#{controller_name}.#{key}",
176
+ :model => full_entry_label,
177
+ :default => :"crud.#{key}")}
178
+ end
179
+
164
180
  class << self
165
181
  # The identifier of the model used for form parameters.
166
182
  # I.e., the symbol of the underscored model name.
@@ -174,5 +190,5 @@ class CrudController < ListController
174
190
  before_render_edit *methods
175
191
  end
176
192
  end
177
-
193
+
178
194
  end