dry_crud 1.2.7 → 1.3.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 +60 -27
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/lib/generators/dry_crud/dry_crud_generator.rb +3 -3
- data/lib/generators/dry_crud/templates/INSTALL +3 -1
- data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +106 -90
- data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +90 -74
- data/lib/generators/dry_crud/templates/app/controllers/render_inheritable.rb +34 -33
- data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +39 -23
- data/lib/generators/dry_crud/templates/app/helpers/list_helper.rb +11 -9
- data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +55 -47
- data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +134 -86
- data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +41 -35
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.erb +1 -0
- data/lib/generators/dry_crud/templates/app/views/crud/edit.html.erb +3 -3
- data/lib/generators/dry_crud/templates/app/views/crud/new.html.erb +2 -2
- data/lib/generators/dry_crud/templates/app/views/crud/show.html.erb +3 -3
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +9 -7
- data/lib/generators/dry_crud/templates/app/views/list/_search.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/list/index.html.erb +4 -4
- data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +3 -1
- data/lib/generators/dry_crud/templates/config/locales/en_crud.yml +63 -0
- data/lib/generators/dry_crud/templates/test/crud_test_model.rb +93 -58
- data/lib/generators/dry_crud/templates/test/custom_assertions.rb +24 -13
- data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +26 -56
- data/lib/generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +47 -41
- data/lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb +28 -24
- data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +20 -34
- data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +39 -53
- data/lib/generators/dry_crud/templates/test/unit/helpers/render_inheritable_test.rb +33 -33
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb +27 -27
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +103 -50
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb +52 -24
- data/test/templates/Gemfile +34 -0
- data/test/templates/app/controllers/ajax_controller.rb +3 -3
- data/test/templates/app/controllers/application_controller.rb +1 -1
- data/test/templates/app/controllers/cities_controller.rb +2 -5
- data/test/templates/app/controllers/people_controller.rb +5 -5
- data/test/templates/app/controllers/vips_controller.rb +6 -11
- data/test/templates/app/helpers/people_helper.rb +2 -2
- data/test/templates/app/models/city.rb +9 -9
- data/test/templates/app/models/person.rb +5 -4
- data/test/templates/app/views/ajax/_actions_index.html.erb +2 -2
- data/test/templates/app/views/cities/_form.html.erb +5 -1
- data/test/templates/app/views/layouts/_menu.html.erb +3 -3
- data/test/templates/app/views/people/_attrs.html.erb +3 -3
- data/test/templates/config/database.yml +22 -0
- data/test/templates/config/locales/en_cities.yml +56 -0
- data/test/templates/config/routes.rb +5 -5
- data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +5 -2
- data/test/templates/db/seeds.rb +38 -29
- data/test/templates/test/functional/cities_controller_test.rb +12 -12
- data/test/templates/test/functional/people_controller_test.rb +10 -10
- 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 | 
            -
            *  | 
| 21 | 
            +
            * Overwrite the <tt>:to_s</tt> method of your models for a human-friendly representation.
         | 
| 22 22 |  | 
| 23 | 
            -
            Version 1.0 | 
| 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  | 
| 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  | 
| 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  | 
| 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  | 
| 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  | 
| 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,  | 
| 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,  | 
| 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 | 
| 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  | 
| 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+  | 
| 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 | 
| 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 | 
            -
             | 
| 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/ | 
| 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  | 
| 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  | 
| 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. | 
| 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 | 
            -
             *  | 
| 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 | 
            -
               | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 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) {  | 
| 63 | 
            -
             | 
| 64 | 
            -
                 | 
| 65 | 
            -
                   | 
| 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) {  | 
| 81 | 
            -
             | 
| 82 | 
            -
                 | 
| 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 =  | 
| 90 | 
            -
             | 
| 91 | 
            -
                 | 
| 92 | 
            -
                   | 
| 93 | 
            -
                     | 
| 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 {  | 
| 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 | 
| 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 | 
            -
              #  | 
| 154 | 
            -
               | 
| 155 | 
            -
             | 
| 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 | 
            -
               | 
| 159 | 
            -
               | 
| 160 | 
            -
               | 
| 161 | 
            -
             | 
| 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
         |