dry_crud 1.7.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +126 -87
- data/VERSION +1 -1
- data/lib/generators/dry_crud/dry_crud_generator.rb +42 -22
- data/lib/generators/dry_crud/templates/INSTALL +5 -5
- data/lib/generators/dry_crud/templates/app/assets/stylesheets/crud.scss +0 -20
- data/lib/generators/dry_crud/templates/app/assets/stylesheets/sample.scss +24 -4
- data/lib/generators/dry_crud/templates/app/controllers/crud/generic_model.rb +89 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud/nestable.rb +70 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud/rememberable.rb +64 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud/render_callbacks.rb +46 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud/responder.rb +31 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud/searchable.rb +55 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud/sortable.rb +63 -0
- data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +66 -69
- data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +23 -326
- data/lib/generators/dry_crud/templates/app/helpers/actions_helper.rb +64 -0
- data/lib/generators/dry_crud/templates/app/helpers/crud/form_builder.rb +331 -0
- data/lib/generators/dry_crud/templates/app/helpers/crud/table_builder.rb +280 -0
- data/lib/generators/dry_crud/templates/app/helpers/form_helper.rb +52 -0
- data/lib/generators/dry_crud/templates/app/helpers/format_helper.rb +164 -0
- data/lib/generators/dry_crud/templates/app/helpers/i18n_helper.rb +85 -0
- data/lib/generators/dry_crud/templates/app/helpers/table_helper.rb +83 -0
- data/lib/generators/dry_crud/templates/app/helpers/utility_helper.rb +84 -0
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.erb +3 -3
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_edit.html.haml +3 -3
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_index.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_index.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_show.html.erb +3 -3
- data/lib/generators/dry_crud/templates/app/views/crud/_actions_show.html.haml +3 -3
- data/lib/generators/dry_crud/templates/app/views/crud/_attrs.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_attrs.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_form.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/_form.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/edit.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/edit.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/new.html.erb +2 -2
- data/lib/generators/dry_crud/templates/app/views/crud/new.html.haml +2 -2
- data/lib/generators/dry_crud/templates/app/views/crud/show.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/crud/show.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/layouts/_flash.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/layouts/_nav.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/layouts/_nav.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +15 -7
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.haml +18 -8
- data/lib/generators/dry_crud/templates/app/views/list/_search.html.erb +3 -3
- data/lib/generators/dry_crud/templates/app/views/list/_search.html.haml +3 -3
- data/lib/generators/dry_crud/templates/app/views/list/index.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/list/index.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +1 -1
- data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.haml +1 -1
- data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.erb +2 -4
- data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.haml +2 -3
- data/lib/generators/dry_crud/templates/config/initializers/field_error_proc.rb +5 -1
- data/lib/generators/dry_crud/templates/config/locales/crud.de.yml +64 -0
- data/lib/generators/dry_crud/templates/config/locales/{en_crud.yml → crud.en.yml} +2 -2
- data/lib/generators/dry_crud/templates/spec/controllers/crud_test_models_controller_spec.rb +241 -231
- data/lib/generators/dry_crud/templates/spec/helpers/crud/form_builder_spec.rb +226 -0
- data/lib/generators/dry_crud/templates/spec/helpers/{standard_table_builder_spec.rb → crud/table_builder_spec.rb} +36 -34
- data/lib/generators/dry_crud/templates/spec/helpers/form_helper_spec.rb +238 -0
- data/lib/generators/dry_crud/templates/spec/helpers/format_helper_spec.rb +244 -0
- data/lib/generators/dry_crud/templates/spec/helpers/i18n_helper_spec.rb +132 -0
- data/lib/generators/dry_crud/templates/spec/helpers/table_helper_spec.rb +265 -0
- data/lib/generators/dry_crud/templates/spec/helpers/utility_helper_spec.rb +74 -0
- data/lib/generators/dry_crud/templates/spec/support/crud_controller_examples.rb +185 -100
- data/lib/generators/dry_crud/templates/spec/support/crud_controller_test_helper.rb +58 -49
- data/lib/generators/dry_crud/templates/test/{functional → controllers}/crud_test_models_controller_test.rb +112 -91
- data/lib/generators/dry_crud/templates/test/{unit/helpers/standard_form_builder_test.rb → helpers/crud/form_builder_test.rb} +79 -62
- data/lib/generators/dry_crud/templates/test/{unit/helpers/standard_table_builder_test.rb → helpers/crud/table_builder_test.rb} +31 -28
- data/lib/generators/dry_crud/templates/test/helpers/custom_assertions_test.rb +85 -0
- data/lib/generators/dry_crud/templates/test/helpers/form_helper_test.rb +129 -0
- data/lib/generators/dry_crud/templates/test/helpers/format_helper_test.rb +163 -0
- data/lib/generators/dry_crud/templates/test/helpers/i18n_helper_test.rb +79 -0
- data/lib/generators/dry_crud/templates/test/helpers/table_helper_test.rb +217 -0
- data/lib/generators/dry_crud/templates/test/helpers/utility_helper_test.rb +63 -0
- data/lib/generators/dry_crud/templates/test/{functional → support}/crud_controller_test_helper.rb +70 -59
- data/lib/generators/dry_crud/templates/test/{crud_test_model.rb → support/crud_test_model.rb} +107 -75
- data/lib/generators/dry_crud/templates/test/support/custom_assertions.rb +83 -0
- metadata +83 -146
- data/Rakefile +0 -211
- data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +0 -168
- data/lib/generators/dry_crud/templates/app/helpers/list_helper.rb +0 -27
- data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +0 -261
- data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +0 -304
- data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +0 -178
- data/lib/generators/dry_crud/templates/spec/helpers/crud_helper_spec.rb +0 -146
- data/lib/generators/dry_crud/templates/spec/helpers/list_helper_spec.rb +0 -154
- data/lib/generators/dry_crud/templates/spec/helpers/standard_form_builder_spec.rb +0 -215
- data/lib/generators/dry_crud/templates/spec/helpers/standard_helper_spec.rb +0 -387
- data/lib/generators/dry_crud/templates/test/custom_assertions.rb +0 -78
- data/lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb +0 -117
- data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +0 -111
- data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +0 -123
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +0 -281
- data/test/templates/Gemfile +0 -46
- data/test/templates/app/controllers/admin/cities_controller.rb +0 -7
- data/test/templates/app/controllers/admin/countries_controller.rb +0 -13
- data/test/templates/app/controllers/ajax_controller.rb +0 -9
- data/test/templates/app/controllers/people_controller.rb +0 -13
- data/test/templates/app/controllers/vips_controller.rb +0 -19
- data/test/templates/app/helpers/cities_helper.rb +0 -9
- data/test/templates/app/helpers/people_helper.rb +0 -8
- data/test/templates/app/models/city.rb +0 -28
- data/test/templates/app/models/country.rb +0 -16
- data/test/templates/app/models/person.rb +0 -12
- data/test/templates/app/views/admin/cities/_actions_index.html.erb +0 -2
- data/test/templates/app/views/admin/cities/_actions_index.html.haml +0 -2
- data/test/templates/app/views/admin/cities/_attrs.html.erb +0 -1
- data/test/templates/app/views/admin/cities/_attrs.html.haml +0 -1
- data/test/templates/app/views/admin/cities/_form.html.erb +0 -7
- data/test/templates/app/views/admin/cities/_form.html.haml +0 -5
- data/test/templates/app/views/admin/cities/_hello.html.erb +0 -1
- data/test/templates/app/views/admin/cities/_hello.html.haml +0 -1
- data/test/templates/app/views/admin/cities/_list.html.erb +0 -3
- data/test/templates/app/views/admin/cities/_list.html.haml +0 -3
- data/test/templates/app/views/admin/countries/_list.html.erb +0 -4
- data/test/templates/app/views/admin/countries/_list.html.haml +0 -3
- data/test/templates/app/views/ajax/_actions_index.html.erb +0 -8
- data/test/templates/app/views/ajax/_actions_index.html.haml +0 -8
- data/test/templates/app/views/ajax/_actions_show.html.erb +0 -4
- data/test/templates/app/views/ajax/_actions_show.html.haml +0 -4
- data/test/templates/app/views/ajax/_form.html.erb +0 -2
- data/test/templates/app/views/ajax/_form.html.haml +0 -2
- data/test/templates/app/views/ajax/_hello.html.erb +0 -1
- data/test/templates/app/views/ajax/_hello.html.haml +0 -1
- data/test/templates/app/views/ajax/ajax.js.erb +0 -1
- data/test/templates/app/views/ajax/ajax.js.haml +0 -1
- data/test/templates/app/views/ajax/edit.js.erb +0 -1
- data/test/templates/app/views/ajax/edit.js.haml +0 -1
- data/test/templates/app/views/ajax/show.js.erb +0 -1
- data/test/templates/app/views/ajax/show.js.haml +0 -1
- data/test/templates/app/views/ajax/update.js.erb +0 -5
- data/test/templates/app/views/ajax/update.js.haml +0 -5
- data/test/templates/app/views/layouts/_nav.html.erb +0 -6
- data/test/templates/app/views/layouts/_nav.html.haml +0 -5
- data/test/templates/app/views/layouts/bootstrap.html.erb +0 -68
- data/test/templates/app/views/layouts/bootstrap.html.haml +0 -49
- data/test/templates/app/views/people/_attrs.html.erb +0 -5
- data/test/templates/app/views/people/_attrs.html.haml +0 -4
- data/test/templates/app/views/people/_list.html.erb +0 -1
- data/test/templates/app/views/people/_list.html.haml +0 -1
- data/test/templates/config/database.yml +0 -21
- data/test/templates/config/locales/en_cities.yml +0 -56
- data/test/templates/config/routes.rb +0 -32
- data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +0 -26
- data/test/templates/db/seeds.rb +0 -74
- data/test/templates/spec/controllers/admin/cities_controller_spec.rb +0 -74
- data/test/templates/spec/controllers/admin/countries_controller_spec.rb +0 -56
- data/test/templates/spec/controllers/people_controller_spec.rb +0 -80
- data/test/templates/spec/routing/cities_routing_spec.rb +0 -11
- data/test/templates/spec/routing/countries_routing_spec.rb +0 -11
- data/test/templates/test/fixtures/cities.yml +0 -11
- data/test/templates/test/fixtures/countries.yml +0 -11
- data/test/templates/test/fixtures/people.yml +0 -14
- data/test/templates/test/functional/admin/cities_controller_test.rb +0 -59
- data/test/templates/test/functional/admin/countries_controller_test.rb +0 -42
- data/test/templates/test/functional/people_controller_test.rb +0 -68
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NjBkMjk0MjMzMjE3ODM1MTMyZmJlODQwNjI0OTlmOTIzYmU5N2Y5MA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NDZlYjRhMmUzMmJkODljYWMwZDUzZjRmYzRmOGUwMDgwZmE5ZTcyMA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NzJkMzU5NjI1MWFmN2JmYzdiOWEzNDBiMDI3OTAyNDk4MDZlMGY1M2VjZjcw
|
10
|
+
YmIwM2ZmYzI2NTllOWViMDVhNmVjMGM5NGQ1YmM5OTY4YWI1YTJkOTA2NTMw
|
11
|
+
OTYwNDI3NDhkMThlMTlkZGNmY2ZkMTY3YjY3MzIyMGNlZTBmNmU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDZmYzhjZDExY2U0NGM5NDYwZDE2MTIwMTM2OWU2ZjI2M2MzN2UwZjE2MmU4
|
14
|
+
NzBmZDZkOTQ2YTZiZjRhZjAyMmZmMWNhOWNkNGIwOWIxY2E0ZTY5OTNkNzI4
|
15
|
+
Yjg0NDY3YTFjNWIwNTY2M2JmMjAyNjBkM2Y1MDU5ZjBlYWYwYzA=
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -2,42 +2,42 @@
|
|
2
2
|
|
3
3
|
{<img src="https://secure.travis-ci.org/codez/dry_crud.png" />}[http://travis-ci.org/codez/dry_crud]
|
4
4
|
|
5
|
-
|
5
|
+
dry_crud generates simple and extendable controllers, views and helpers that support you to DRY up the CRUD code in your Rails projects. Start with these artifacts and build a clean base to efficiently develop your application upon.
|
6
6
|
|
7
|
-
Create your Rails application directly with the
|
7
|
+
Create your Rails application directly with the dry_crud application template:
|
8
8
|
|
9
9
|
rails new APP_NAME -m https://raw.github.com/codez/dry_crud/master/template.rb
|
10
|
-
|
10
|
+
|
11
11
|
If your application already exists or you prefer the DIY way, then install the Gem (<tt>gem install dry_crud</tt>), add it to your Gemfile and run the generator. You may remove the Gemfile entry again afterwards, it is not required anymore.
|
12
12
|
|
13
13
|
rails generate dry_crud [--templates haml] [--tests rspec]
|
14
|
-
|
15
|
-
By default, DRY CRUD generates ERB templates and Test::Unit tests. Pass the options above to generate HAML templates and/or RSpec examples instead.
|
16
14
|
|
17
|
-
|
15
|
+
By default, dry_crud generates ERB templates and Test::Unit tests. Pass the options above to generate HAML templates and/or RSpec examples instead.
|
16
|
+
|
17
|
+
To integrate dry_crud into your code, only a few additions are required:
|
18
18
|
|
19
|
-
* For uniform CRUD functionality, just subclass your controllers from
|
20
|
-
* Overwrite the
|
19
|
+
* For uniform CRUD functionality, just subclass your controllers from CrudController.
|
20
|
+
* Overwrite the +to_s+ method of your models for a human-friendly representation in captions.
|
21
21
|
|
22
|
-
Version
|
22
|
+
Version 2.0 and higher are compatible with Rails 4 and Rails 3.2. dry_crud is tested with Ruby 1.9.3, 2.0.0 and JRuby. If you are using Ruby 1.8.7, please refer to version 1.7.0.
|
23
23
|
|
24
24
|
== Overview
|
25
25
|
|
26
26
|
In most Rails applications, you have some models that require basic CRUD (create, read, update, delete) functionality. There are various possibilities like Rails scaffolding, {Inherited Resources}[https://github.com/josevalim/inherited_resources] or {Dry Scaffold}[http://github.com/grimen/dry_scaffold]. Still, various parts in your application remain duplicated. While you might pull up common methods into a common superclass controller, most views still contain very similar code. And then you also have to remember the entire API of these frameworks.
|
27
27
|
|
28
|
-
Enter
|
28
|
+
Enter dry_crud.
|
29
29
|
|
30
30
|
<b>
|
31
|
-
The main idea of
|
31
|
+
The main idea of dry_crud is to concentrate basic functionality of your application, like CRUD actions, uniform formatting, forms and tables into specifically extendable units. dry_crud generates various foundation classes that you may browse easily and adapt freely to your application's needs. For each model, you may transparently customize arbitrary parts or just fallback to the general behavior. This applies not only for controllers, but also for view templates and helpers. There is no black box your code depends on. You lay the foundation that fits your application best.
|
32
32
|
</b>
|
33
33
|
|
34
|
-
|
34
|
+
dry_crud is a Rails generator. All code resides in your application and is open for you to inspect and to extend. You may pick whatever you consider useful or adapt what is not sufficient. Even if you do not require any CRUD functionality, you might find some helpers simplifying your work. There are no runtime dependencies to the dry_crud gem. Having said this, dry_crud does not want to provide a maximum of functionality that requires a lot of configuration, but rather a clean and lightweight foundation to build your application's requirements upon. This is why dry_crud comes as a generator and not as a Rails plugin.
|
35
35
|
|
36
|
-
|
36
|
+
dry_crud does not depend on any other plugins, but easily allows you to integrate them in order to unify the behavior of your CRUD controllers. You might even use the plugins mentioned above to adapt your generated CrudController base class. All classes come with thorough tests that provide you with a solid foundation for implementing your own adaptions.
|
37
37
|
|
38
|
-
A basic CSS gets you started with your application's layout. For advanced needs,
|
38
|
+
A basic CSS gets you started with your application's layout. For advanced needs, dry_crud supports the styles and classes used in {Bootstrap}[http://twitter.github.com/bootstrap/]. A great design never was so close.
|
39
39
|
|
40
|
-
If you find yourself adapting the same parts of
|
40
|
+
If you find yourself adapting the same parts of dry_crud for your applications over and over, please feel free to {fork me on Github}[http://github.com/codez/dry_crud].
|
41
41
|
|
42
42
|
See the Examples section for some use cases and the Generated Files section below for details on the single classes and templates.
|
43
43
|
|
@@ -45,12 +45,15 @@ See the Examples section for some use cases and the Generated Files section belo
|
|
45
45
|
|
46
46
|
=== Controller with CRUD functionality
|
47
47
|
|
48
|
-
Say you want to manage a +Person+ model. Create the following controller and overwrite the
|
48
|
+
Say you want to manage a +Person+ model. Create the following controller and overwrite the +to_s+ method of your model for a human-friendly representation used in page titles.
|
49
49
|
|
50
50
|
<tt>app/controllers/people_controller.rb</tt>:
|
51
51
|
class PeopleController < CrudController
|
52
|
+
self.permitted_attrs = [:firstname, :lastname, :birthday, :sex, :city_id]
|
52
53
|
end
|
53
54
|
|
55
|
+
The +permitted_attrs+ define the parameter attributes allowed when creating or updating a model entry (see {Strong Paramters}[http://api.rubyonrails.org/classes/ActionController/StrongParameters.html]).
|
56
|
+
|
54
57
|
<tt>app/models/person.rb</tt>:
|
55
58
|
class Person
|
56
59
|
def to_s
|
@@ -58,12 +61,12 @@ Say you want to manage a +Person+ model. Create the following controller and ove
|
|
58
61
|
end
|
59
62
|
end
|
60
63
|
|
61
|
-
That's it. You have a sortable overview of all people, detail pages and forms to edit and create
|
64
|
+
That's it. You have a sortable overview of all people, detail pages and forms to edit and create people. Of course, you may delete people as well. By default, all attributes are displayed and formatted according to their column type wherever they appear. This applies for the input fields as well.
|
62
65
|
|
63
66
|
|
64
67
|
==== Customize single views
|
65
68
|
|
66
|
-
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:
|
69
|
+
Well, maybe there are certain attributes you do not want to display in the people list, or others that are not editable in the form. No problem, simply create a <tt> _list</tt> partial in <tt>app/views/people/_list.html.erb</tt> to customize this:
|
67
70
|
|
68
71
|
<%= crud_table :lastname, :firstname, :city, :sex %>
|
69
72
|
|
@@ -72,7 +75,7 @@ This only displays these three attributes in the table. All other templates, as
|
|
72
75
|
|
73
76
|
==== Adapt general behavior
|
74
77
|
|
75
|
-
Next, let's adapt a part of the general behavior used in all CRUD controllers. As an example, we include pagination with kaminari[https://github.com/amatsuda/kaminari] in all our overview tables:
|
78
|
+
Next, let's adapt a part of the general behavior used in all CRUD controllers. As an example, we include pagination with kaminari[https://github.com/amatsuda/kaminari] in all our overview tables:
|
76
79
|
|
77
80
|
In <tt>app/controllers/list_controller.rb</tt>, change the list_entries method to
|
78
81
|
|
@@ -83,89 +86,74 @@ In <tt>app/controllers/list_controller.rb</tt>, change the list_entries method t
|
|
83
86
|
In <tt>app/views/list/index.html.erb</tt>, add the following line for the pagination links:
|
84
87
|
<%= paginate entries %>
|
85
88
|
|
86
|
-
And we are done
|
89
|
+
And we are done. All our controllers inheriting from ListController, including above +PeopleController+, now have paginated index views. Because our customization for the people table is in the separate <tt>_list</tt> partial, no further modifications are required.
|
90
|
+
|
87
91
|
|
88
92
|
==== Special formatting for selected attributes
|
89
93
|
|
90
|
-
Sometimes, the default formatting provided by
|
94
|
+
Sometimes, the default formatting provided by +format_attr+ 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 class and attribute name:
|
91
95
|
|
92
96
|
In <tt>app/helpers/people.rb</tt>:
|
93
97
|
def format_person_sex(person)
|
94
98
|
person.sex ? 'female' : 'male'
|
95
99
|
end
|
96
|
-
|
100
|
+
|
97
101
|
Should you have attributes with the same name for multiple models that you want to be formatted the same way, you may define a helper method <tt>format_{attr}</tt> for these attributes.
|
98
102
|
|
99
|
-
By the way: The method
|
103
|
+
By the way: The method +f+ in FormatHelper uniformly formats arbitrary values according to their class.
|
100
104
|
|
101
105
|
|
102
|
-
====
|
106
|
+
==== Sorting and filtering the index list
|
103
107
|
|
104
|
-
|
108
|
+
The entries listed on the index page are automatically sortable by each displayed database column. To apply a default sorting order, define the following class attribute in the controller:
|
105
109
|
|
106
110
|
In <tt>app/controllers/people_controller.rb</tt>:
|
107
|
-
self.
|
111
|
+
self.default_sort = 'lastname, firstname'
|
108
112
|
|
109
|
-
|
113
|
+
When you display computed values in your list table, you may define sort mappings to enable sorting of these columns:
|
110
114
|
|
115
|
+
In <tt>app/controllers/people_controller.rb</tt>:
|
116
|
+
self.sort_mappings = {age: 'birthday', city_id: 'cities.name'}
|
111
117
|
|
112
|
-
|
113
|
-
|
114
|
-
As a last example, let's say we have added a custom input field that must specially processed. Instead of overwriting the entire update action, it is possible to register callbacks for the +create+, +update+, +save+ (= +create+ and +update+) and +destroy+ actions. They work very similarliy like the callbacks on ActiveRecord. For each action, before and after callbacks are run. Before callbacks may also prevent the action from being executed when returning false. Here is some code:
|
118
|
+
There is also a simple search functionality (based on SQL LIKE queries) implemented in Crud::Searchable. Define an array of columns in your controller's +search_columns+ class variable to make the entries searchable by these fields:
|
115
119
|
|
116
120
|
In <tt>app/controllers/people_controller.rb</tt>:
|
117
|
-
|
118
|
-
before_destroy :delete_picture
|
119
|
-
|
120
|
-
def upload_picture
|
121
|
-
store_file(params[:person][:picture]) if params[:person][:picture]
|
122
|
-
end
|
123
|
-
|
124
|
-
def delete_picture
|
125
|
-
if !perform_delete_picture(entry.picture)
|
126
|
-
flash.alert = 'Could not delete picture'
|
127
|
-
false
|
128
|
-
end
|
129
|
-
end
|
121
|
+
self.search_columns = [:firstname, :lastname]
|
130
122
|
|
131
|
-
|
123
|
+
If you have search columns defined, a search box will be displayed in the index view that enables filtering of the displayed entries.
|
132
124
|
|
133
|
-
In <tt>app/controllers/people_controller.rb</tt>:
|
134
|
-
before_render_form :set_hometowns
|
135
|
-
|
136
|
-
def set_hometowns
|
137
|
-
@hometowns = City.where(:country => entry.country)
|
138
|
-
end
|
139
125
|
|
140
126
|
=== Standard Tables and Forms
|
141
127
|
|
142
|
-
|
128
|
+
dry_crud provides two builder classes for update/create forms and tables for displaying entries of one model. They may be used all over your application to DRY up the form and table code. Normally, they are used with the corresponding methods from TableHelper and FormHelper. In there are generic helper methods (+plain_table+ and +plain_form+/+standard_form+) and slightly enhanced ones for views of subclasses of CrudController (+crud_table+ and +crud_form+).
|
143
129
|
|
144
130
|
==== Tables
|
145
131
|
|
146
|
-
|
147
|
-
<%=
|
132
|
+
The following code defines a table with some attribute columns for a list of same-type entries. Columns get a header corresponding to the attribute name:
|
133
|
+
<%= plain_table(@people) do |t|
|
148
134
|
t.sortable_attrs :lastname, :firstname
|
149
135
|
end %>
|
150
136
|
|
151
137
|
If entries is empty, a basic 'No entries found' message is rendered instead of the table.
|
152
138
|
|
153
|
-
To render custom columns, use the
|
154
|
-
<%=
|
139
|
+
To render custom columns, use the +col+ method with an appropriate block:
|
140
|
+
<%= plain_table(@people) do |t|
|
155
141
|
t.sortable_attrs :lastname, :firstname
|
156
|
-
t.col('', :
|
142
|
+
t.col('', class: 'center') {|entry| image_tag(entry.picture) }
|
157
143
|
t.attr :street
|
158
144
|
t.col('Map') {|entry| link_to(entry.city, "http://maps.google.com/?q=#{entry.city}" }
|
159
145
|
end %>
|
160
146
|
|
147
|
+
For views of subclasses of ListController, you can directly use the +crud_table+ helper method, where you do not have to pass the <tt>@people</tt> list explicitly and actions are added automatically.
|
148
|
+
|
161
149
|
==== Forms
|
162
150
|
|
163
151
|
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:
|
164
152
|
|
165
|
-
<%=
|
153
|
+
<%= standard_form(@person, :firstname, :lastname, :age, :city) -%>
|
166
154
|
|
167
155
|
Of course, custom input fields may be defined as well:
|
168
|
-
<%=
|
156
|
+
<%= standard_form(@person, url: custom_update_person_path(@person.id)) do |f| %>
|
169
157
|
<%= f.labeled_input_fields :firstname, :lastname %>
|
170
158
|
<%= f.labeled(:sex) do %>
|
171
159
|
<%= f.radio_button :sex, true %> female
|
@@ -175,34 +163,64 @@ Of course, custom input fields may be defined as well:
|
|
175
163
|
<%= f.labeled_file_field :picture %>
|
176
164
|
<% end %>
|
177
165
|
|
178
|
-
Even +belongs_to+ associations are automatically rendered with a select field. By default, all entries from the associated model are used as options. To customize this, either define an instance variable with the same name as the association in your controller, or pass a <tt
|
179
|
-
<%= f.belongs_to_field :hometown, :
|
166
|
+
Even +belongs_to+ associations are automatically rendered with a select field. By default, all entries from the associated model are used as options. To customize this, either define an instance variable with the same name as the association in your controller, or pass a <tt>list</tt> option:
|
167
|
+
<%= f.belongs_to_field :hometown, list: City.where(country: @person.country) %>
|
180
168
|
|
181
|
-
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
|
169
|
+
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.
|
182
170
|
|
183
|
-
Optionally, +has_and_belongs_to_many+ and +has_many+ associations can be rendered with a multi-select field. Similar to a +belongs_to+ association, all entries from the associated model are used, but can be overwritten using the <tt
|
184
|
-
<%= f.has_many_field :visited_cities, :
|
171
|
+
Optionally, +has_and_belongs_to_many+ and +has_many+ associations can be rendered with a multi-select field. Similar to a +belongs_to+ association, all entries from the associated model are used, but can be overwritten using the <tt>list</tt> option:
|
172
|
+
<%= f.has_many_field :visited_cities, list: City.where(is_touristic: true) %>
|
185
173
|
|
186
174
|
And yes again, the same advice for where to put finder logic applies here as well.
|
187
175
|
|
188
176
|
<b>Note:</b> +has_and_belongs_to_many+ and +has_many+ associations are not automatically rendered in a form, you have to explicitly include these attributes. You might also want to stylize the multi-select widget, for example with a {jQuery UI Multiselect}[http://www.quasipartikel.at/multiselect/].
|
189
177
|
|
178
|
+
|
190
179
|
=== Nested Resources
|
191
180
|
|
192
|
-
In case you define nested resources, your
|
181
|
+
In case you define nested resources, your CrudController subclass should know. Listing and creating entries as well as displaying links for these resources is dependent on the nesting hierarchy. This is how you declare the namespaces and parent resources in your controller:
|
193
182
|
|
194
183
|
self.nesting = :my_namspace, ParentResource
|
195
|
-
|
184
|
+
|
196
185
|
This declaration is for a controller nested in +parent_resources+ within a +:my_namespace+ scope. +ParentResource+ is the corresponding +ActiveRecord+ model. The request param +:parent_resource_id+ is used to load the parent entry, which in turn is used to filter the entries listed and created in your controller. For all parent resources, a corresponding instance variable is created.
|
197
186
|
|
198
|
-
The <tt>
|
187
|
+
The <tt>Crud::Nestable</tt> module defines this basic behaviour. For more complex setups, have a look there and adjust it to your needs.
|
188
|
+
|
189
|
+
|
190
|
+
=== CRUD controller callbacks
|
191
|
+
|
192
|
+
As a last example, let's say we have added a custom input field that must specially processed. Instead of overwriting the entire update action, it is possible to register callbacks for the +create+, +update+, +save+ (= +create+ and +update+) and +destroy+ actions. They work very similarliy like the callbacks on ActiveRecord. For each action, before and after callbacks are run. Before callbacks may also prevent the action from being executed when returning false. Here is some code:
|
193
|
+
|
194
|
+
In <tt>app/controllers/people_controller.rb</tt>:
|
195
|
+
after_save :upload_picture
|
196
|
+
before_destroy :delete_picture
|
197
|
+
|
198
|
+
def upload_picture
|
199
|
+
store_file(params[:person][:picture]) if params[:person][:picture]
|
200
|
+
end
|
201
|
+
|
202
|
+
def delete_picture
|
203
|
+
if !perform_delete_picture(entry.picture)
|
204
|
+
flash.alert = 'Could not delete picture'
|
205
|
+
false
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
Beside these "action" callbacks, there is also a set of +before_render+ callbacks that are called whenever a certain view is rendered. They are available for the +index+, +show+, +new+, +edit+ and +form+ (= +new+ and +edit+) views. These callbacks are not only called for the corresponding action, but, for example, also when the +new+ view is going to be rendered from an unsuccessfull +create+ action. Say you need to prepare additional variables whenever the form is rendered:
|
210
|
+
|
211
|
+
In <tt>app/controllers/people_controller.rb</tt>:
|
212
|
+
before_render_form :set_hometowns
|
213
|
+
|
214
|
+
def set_hometowns
|
215
|
+
@hometowns = City.where(country: entry.country)
|
216
|
+
end
|
199
217
|
|
200
218
|
|
201
219
|
=== Internationalization (I18N)
|
202
220
|
|
203
|
-
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.
|
221
|
+
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.
|
204
222
|
|
205
|
-
To represent your controller hierarchy, a special translation helper
|
223
|
+
To represent your controller hierarchy, a special translation helper +ti+ looks up keys along the hierarchy in the following order:
|
206
224
|
{controller_name}.{template_name}.{key}
|
207
225
|
{controller_name}.{action_name}.{key}
|
208
226
|
{controller_name}.global.{key}
|
@@ -215,7 +233,7 @@ To represent your controller hierarchy, a special translation helper <tt>:ti</tt
|
|
215
233
|
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:
|
216
234
|
people.index.title = "The People"
|
217
235
|
|
218
|
-
Otherwise, the lookup for the title would fallback on the
|
236
|
+
Otherwise, the lookup for the title would fallback on the ListController's key <tt>list.index.title</tt>.
|
219
237
|
|
220
238
|
This lookup mechanism also allows you to easily define per-controller overridable text snippets in your views.
|
221
239
|
|
@@ -226,27 +244,48 @@ All generated files are supposed to provide a reasonable foundation for the CRUD
|
|
226
244
|
|
227
245
|
=== Controller:
|
228
246
|
|
229
|
-
{controller/crud_controller.rb}[http://codez.ch/dry_crud
|
247
|
+
{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.
|
248
|
+
|
249
|
+
{controller/list_controller.rb}[http://codez.ch/dry_crud?q=ListController]:: Abstract controller providing a basic list action. Use this controller if you require read-only functionality. It includes the following modules.
|
250
|
+
|
251
|
+
{controller/crud/generic_model.rb}[http://codez.ch/dry_crud?q=Crud::GenericModel]:: Work with the model whose name corrsponds to the controller's name.
|
252
|
+
|
253
|
+
{controller/crud/nestable.rb}[http://codez.ch/dry_crud?q=Crud::Nestable]:: Provides functionality to easily nest controllers/resources.
|
230
254
|
|
231
|
-
{controller/
|
255
|
+
{controller/crud/rememberable.rb}[http://codez.ch/dry_crud?q=Crud::Rememberable]:: Remembers certain params of the index action in order to return to the same list after an entry was viewed or edited.
|
232
256
|
|
257
|
+
{controller/crud/searchable.rb}[http://codez.ch/dry_crud?q=Crud::Searchable]:: Search functionality for the index table.
|
258
|
+
|
259
|
+
{controller/crud/sortable.rb}[http://codez.ch/dry_crud?q=Crud::Sortable]:: Sort functionality for the index table.
|
260
|
+
|
261
|
+
{controller/crud/render_callbacks.rb}[http://codez.ch/dry_crud?q=Crud::RenderCallbacks]:: Provide +before_render+ callbacks to controllers.
|
262
|
+
|
263
|
+
{controller/crud/responder.rb}[http://codez.ch/dry_crud?q=Crud::Responder]:: Responder used by the CrudController to handle the +path_args+.
|
233
264
|
|
234
265
|
=== Helpers:
|
235
266
|
|
236
|
-
{helpers/
|
267
|
+
{helpers/crud/table_builder.rb}[http://codez.ch/dry_crud?q=Crud::TableBuilder]:: A simple helper object to easily define tables listing several rows of the same data type.
|
268
|
+
|
269
|
+
{helpers/crud/form_builder.rb}[http://codez.ch/dry_crud?q=Crud::FormBuilder]:: A form builder that automatically selects the corresponding input type for ActiveRecord columns. Input elements are rendered together with a label by default.
|
270
|
+
|
271
|
+
{helpers/table_helper.rb}[http://codez.ch/dry_crud?q=TableHelper]:: Create tables to list multiple models with Crud::TableBuilder. Contains a standardized and a custom definable table.
|
272
|
+
|
273
|
+
{helpers/form_helper.rb}[http://codez.ch/dry_crud?q=FormHelper]:: Create forms to edit models with Crud::FormBuilder. Contains a standardized and a custom definable form.
|
274
|
+
|
275
|
+
{helpers/format_helper.rb}[http://codez.ch/dry_crud?q=FormatHelper]:: Format attribute and basic values according to their database or Ruby type.
|
237
276
|
|
238
|
-
{helpers/
|
277
|
+
{helpers/actions_helper.rb}[http://codez.ch/dry_crud?q=ActionsHelper]:: Uniform action links for the most common crud actions.
|
239
278
|
|
240
|
-
{helpers/
|
279
|
+
{helpers/i18n_helper.rb}[http://codez.ch/dry_crud?q=I18nHelper]:: Translation helpers extending Rails' +translate+ helper to support translation inheritance over the controller class hierarchy.
|
241
280
|
|
242
|
-
{helpers/
|
281
|
+
{helpers/utility_helper.rb}[http://codez.ch/dry_crud?q=UtilityHelper]:: View helpers for basic functions used in various other helpers.
|
243
282
|
|
244
|
-
{helpers/standard_form_builder.rb}[http://codez.ch/dry_crud/StandardFormBuilder.html]:: A form builder that automatically selects the corresponding input type for ActiveRecord columns. Input elements are rendered together with a label by default.
|
245
283
|
|
246
284
|
|
247
285
|
=== Views:
|
248
286
|
|
249
287
|
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.
|
288
|
+
All templates are available as HAML as well.
|
250
289
|
|
251
290
|
==== List
|
252
291
|
|
@@ -262,7 +301,7 @@ views/list/_actions_index.html.erb:: The action links available in the index vie
|
|
262
301
|
|
263
302
|
views/crud/show.html.erb:: The show view displaying all the attributes of one entry and the various actions to perform on it.
|
264
303
|
|
265
|
-
views/crud/_attrs.html.erb:: A partial defining the attributes to be displayed in the show view.
|
304
|
+
views/crud/_attrs.html.erb:: A partial defining the attributes to be displayed in the show view.
|
266
305
|
|
267
306
|
views/crud/_list.html.erb:: A partial defining the table in the index view with various links to manipulate the entries.
|
268
307
|
|
@@ -290,33 +329,33 @@ views/layouts/_flash.html.erb:: An simple partial to display the various flash m
|
|
290
329
|
|
291
330
|
views/layouts/_nav.html.erb:: An empty file to put your navigation into. Included from <tt>crud.html.erb</tt>.
|
292
331
|
|
293
|
-
app/assets/stylesheets/crud.scss:: A simple SCSS with all the classes and ids used in the CRUD code.
|
332
|
+
app/assets/stylesheets/crud.scss:: A simple SCSS with all the classes and ids used in the CRUD code.
|
294
333
|
|
295
334
|
app/assets/images/action/*.png:: Some sample action icons from the {Open Icon Library}[http://openiconlibrary.sourceforge.net].
|
296
335
|
|
297
336
|
|
298
337
|
=== Tests:
|
299
338
|
|
300
|
-
|
339
|
+
test/support/crud_test_model.rb:: A dummy model to run CRUD tests against.
|
301
340
|
|
302
|
-
{test/custom_assertions.rb}[http://codez.ch/dry_crud
|
341
|
+
{test/support/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.
|
303
342
|
|
304
|
-
{test/
|
343
|
+
{test/support/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.
|
305
344
|
|
306
|
-
test/
|
345
|
+
test/controllers/crud_test_models_controller_test.rb:: Functional tests for the basic CrudController functionality.
|
307
346
|
|
308
|
-
test/
|
347
|
+
test/helpers/*_test.rb:: Tests for the provided helper implementations and a great base to test your adaptions of the CRUD code.
|
309
348
|
|
310
349
|
|
311
350
|
=== Specs:
|
312
351
|
|
313
352
|
spec/support/crud_controller_examples.rb:: A whole set of shared exampled to include into your controller specs. See <tt>spec/controllers/crud_test_models_controller_spec.rb</tt> for usage. So for each new CRUD controller, you get all the basic specs for free.
|
314
353
|
|
315
|
-
spec/support/crud_controller_test_helper.rb:: Convenience methods used by the crud controller examples.
|
354
|
+
{spec/support/crud_controller_test_helper.rb}[http://codez.ch/dry_crud?q=CrudControllerTestHelper::ClassMethods]:: Convenience methods used by the crud controller examples.
|
316
355
|
|
317
|
-
|
356
|
+
spec/support/crud_test_model.rb:: A dummy model to run CRUD tests against.
|
318
357
|
|
319
|
-
spec/controllers/crud_test_models_controller_spec.rb:: Controller specs to test the basic
|
358
|
+
spec/controllers/crud_test_models_controller_spec.rb:: Controller specs to test the basic CrudController functionality.
|
320
359
|
|
321
|
-
spec/helpers/*_spec.rb:: The specs for all the helpers included in
|
360
|
+
spec/helpers/*_spec.rb:: The specs for all the helpers included in dry_crud and a great base to test your adaptions of the CRUD code.
|
322
361
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0
|
@@ -1,42 +1,62 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require 'rails/generators'
|
2
4
|
|
5
|
+
# Copies all dry_crud files to the rails application.
|
3
6
|
class DryCrudGenerator < Rails::Generators::Base
|
4
7
|
|
5
8
|
class_options %w(templates -t) => 'erb'
|
6
9
|
class_options %w(tests) => 'testunit'
|
7
10
|
|
8
|
-
|
9
11
|
def self.source_root
|
10
12
|
File.join(File.dirname(__FILE__), 'templates')
|
11
13
|
end
|
12
14
|
|
15
|
+
# copy everything in template subfolders
|
13
16
|
def install_dry_crud
|
14
|
-
# copy everything in template subfolders
|
15
|
-
exclude_template = options[:templates].downcase == 'haml' ? '.erb' : '.haml'
|
16
|
-
|
17
|
-
exclude_test_dir = case options[:tests].downcase
|
18
|
-
when 'rspec' then 'test'
|
19
|
-
when 'all' then 'exclude_nothing'
|
20
|
-
else 'spec'
|
21
|
-
end
|
22
|
-
|
23
17
|
Dir.chdir(self.class.source_root) do
|
24
18
|
Dir.glob(File.join('**', '**')).sort.each do |file_source|
|
25
|
-
if
|
26
|
-
!file_source.end_with?(exclude_template) &&
|
27
|
-
!file_source.start_with?(exclude_test_dir) &&
|
28
|
-
file_source != 'INSTALL'
|
29
|
-
copy_file(file_source)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
unless exclude_test_dir == 'spec'
|
34
|
-
copy_file(File.join('test', 'crud_test_model.rb'),
|
35
|
-
File.join('spec', 'support', 'crud_test_model.rb'))
|
19
|
+
copy_file_source(file_source) if should_copy?(file_source)
|
36
20
|
end
|
21
|
+
copy_crud_test_model
|
22
|
+
end
|
23
|
+
|
24
|
+
readme 'INSTALL'
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def should_copy?(file_source)
|
30
|
+
!File.directory?(file_source) &&
|
31
|
+
!file_source.end_with?(exclude_template) &&
|
32
|
+
!file_source.start_with?(exclude_test_dir) &&
|
33
|
+
file_source != 'INSTALL'
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy_file_source(file_source)
|
37
|
+
if file_source.end_with?('.erb')
|
38
|
+
copy_file(file_source)
|
39
|
+
else
|
40
|
+
template(file_source)
|
37
41
|
end
|
42
|
+
end
|
38
43
|
|
39
|
-
|
44
|
+
def copy_crud_test_model
|
45
|
+
unless exclude_test_dir == 'spec'
|
46
|
+
template(File.join('test', 'support', 'crud_test_model.rb'),
|
47
|
+
File.join('spec', 'support', 'crud_test_model.rb'))
|
48
|
+
end
|
40
49
|
end
|
41
50
|
|
51
|
+
def exclude_template
|
52
|
+
options[:templates].downcase == 'haml' ? '.erb' : '.haml'
|
53
|
+
end
|
54
|
+
|
55
|
+
def exclude_test_dir
|
56
|
+
case options[:tests].downcase
|
57
|
+
when 'rspec' then 'test'
|
58
|
+
when 'all' then 'exclude_nothing'
|
59
|
+
else 'spec'
|
60
|
+
end
|
61
|
+
end
|
42
62
|
end
|