dry_crud 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +24 -19
- data/Rakefile +12 -4
- data/VERSION +1 -1
- data/lib/generators/dry_crud/dry_crud_generator.rb +7 -7
- data/lib/generators/dry_crud/templates/app/assets/stylesheets/crud.scss +18 -7
- data/lib/generators/dry_crud/templates/app/assets/stylesheets/sample.scss +13 -18
- data/lib/generators/dry_crud/templates/app/controllers/crud_controller.rb +74 -87
- data/lib/generators/dry_crud/templates/app/controllers/list_controller.rb +95 -50
- data/lib/generators/dry_crud/templates/app/helpers/crud_helper.rb +11 -11
- data/lib/generators/dry_crud/templates/app/helpers/list_helper.rb +7 -7
- data/lib/generators/dry_crud/templates/app/helpers/standard_form_builder.rb +55 -27
- data/lib/generators/dry_crud/templates/app/helpers/standard_helper.rb +83 -30
- data/lib/generators/dry_crud/templates/app/helpers/standard_table_builder.rb +5 -13
- data/lib/generators/dry_crud/templates/app/views/layouts/_flash.html.erb +1 -4
- data/lib/generators/dry_crud/templates/app/views/layouts/_flash.html.haml +1 -3
- data/lib/generators/dry_crud/templates/app/views/layouts/_nav.html.erb +6 -6
- data/lib/generators/dry_crud/templates/app/views/layouts/_nav.html.haml +5 -3
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.erb +13 -11
- data/lib/generators/dry_crud/templates/app/views/layouts/crud.html.haml +15 -15
- data/lib/generators/dry_crud/templates/app/views/shared/_error_messages.html.erb +10 -10
- data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.erb +2 -2
- data/lib/generators/dry_crud/templates/app/views/shared/_labeled.html.haml +2 -2
- data/lib/generators/dry_crud/templates/config/initializers/field_error_proc.rb +1 -0
- data/lib/generators/dry_crud/templates/config/locales/en_crud.yml +1 -0
- data/lib/generators/dry_crud/templates/test/crud_test_model.rb +72 -17
- data/lib/generators/dry_crud/templates/test/custom_assertions.rb +1 -1
- data/lib/generators/dry_crud/templates/test/functional/crud_controller_test_helper.rb +42 -26
- data/lib/generators/dry_crud/templates/test/functional/crud_test_models_controller_test.rb +135 -29
- data/lib/generators/dry_crud/templates/test/unit/custom_assertions_test.rb +4 -4
- data/lib/generators/dry_crud/templates/test/unit/helpers/crud_helper_test.rb +4 -2
- data/lib/generators/dry_crud/templates/test/unit/helpers/list_helper_test.rb +2 -0
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_form_builder_test.rb +94 -16
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_helper_test.rb +58 -18
- data/lib/generators/dry_crud/templates/test/unit/helpers/standard_table_builder_test.rb +4 -4
- data/test/templates/Gemfile +1 -0
- data/test/templates/app/controllers/admin/cities_controller.rb +0 -7
- data/test/templates/app/controllers/admin/countries_controller.rb +2 -3
- data/test/templates/app/controllers/ajax_controller.rb +2 -0
- data/test/templates/app/controllers/people_controller.rb +1 -1
- data/test/templates/app/models/city.rb +2 -0
- data/test/templates/app/models/country.rb +2 -0
- data/test/templates/app/models/person.rb +2 -0
- data/test/templates/app/views/admin/cities/_attrs.html.erb +1 -0
- data/test/templates/app/views/admin/cities/_attrs.html.haml +1 -0
- data/test/templates/app/views/admin/cities/_form.html.erb +7 -1
- data/test/templates/app/views/admin/cities/_form.html.haml +5 -1
- data/test/templates/app/views/admin/cities/_list.html.erb +1 -4
- data/test/templates/app/views/admin/cities/_list.html.haml +1 -3
- data/test/templates/app/views/ajax/_actions_show.html.erb +4 -0
- data/test/templates/app/views/ajax/_actions_show.html.haml +4 -0
- data/test/templates/app/views/ajax/_form.html.erb +2 -0
- data/test/templates/app/views/ajax/_form.html.haml +2 -0
- data/test/templates/app/views/ajax/edit.js.erb +1 -0
- data/test/templates/app/views/ajax/edit.js.haml +1 -0
- data/test/templates/app/views/ajax/show.js.erb +1 -0
- data/test/templates/app/views/ajax/show.js.haml +1 -0
- data/test/templates/app/views/ajax/update.js.erb +5 -0
- data/test/templates/app/views/ajax/update.js.haml +5 -0
- data/test/templates/app/views/layouts/_nav.html.erb +6 -0
- data/test/templates/app/views/layouts/_nav.html.haml +5 -0
- data/test/templates/app/views/layouts/bootstrap.html.erb +68 -0
- data/test/templates/app/views/layouts/bootstrap.html.haml +49 -0
- data/test/templates/app/views/people/_attrs.html.erb +2 -2
- data/test/templates/app/views/people/_attrs.html.haml +2 -2
- data/test/templates/config/routes.rb +5 -5
- data/test/templates/db/migrate/20100511174904_create_people_and_cities.rb +1 -1
- data/test/templates/db/seeds.rb +52 -52
- data/test/templates/test/functional/admin/cities_controller_test.rb +15 -15
- data/test/templates/test/functional/admin/countries_controller_test.rb +4 -5
- data/test/templates/test/functional/people_controller_test.rb +32 -4
- metadata +22 -9
- data/lib/generators/dry_crud/templates/app/views/layouts/_menu.html.erb +0 -3
- data/lib/generators/dry_crud/templates/app/views/layouts/_menu.html.haml +0 -3
- data/test/templates/app/views/layouts/_menu.html.erb +0 -3
- data/test/templates/app/views/layouts/_menu.html.haml +0 -3
data/README.rdoc
CHANGED
@@ -72,17 +72,16 @@ This only displays these three attributes in the table. All other templates, as
|
|
72
72
|
|
73
73
|
==== Adapt general behavior
|
74
74
|
|
75
|
-
Next, let's adapt a part of the general behavior used in all CRUD controllers. As an example, we include pagination with
|
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:
|
76
76
|
|
77
|
-
In <tt>app/controllers/list_controller.rb</tt>, change the
|
77
|
+
In <tt>app/controllers/list_controller.rb</tt>, change the list_entries method to
|
78
78
|
|
79
|
-
def
|
80
|
-
|
81
|
-
respond_with @entries
|
79
|
+
def list_entries
|
80
|
+
model_scope.page(params[:page])
|
82
81
|
end
|
83
82
|
|
84
83
|
In <tt>app/views/list/index.html.erb</tt>, add the following line for the pagination links:
|
85
|
-
<%=
|
84
|
+
<%= paginate entries %>
|
86
85
|
|
87
86
|
And we are done again. 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.
|
88
87
|
|
@@ -123,7 +122,7 @@ In <tt>app/controllers/people_controller.rb</tt>:
|
|
123
122
|
end
|
124
123
|
|
125
124
|
def delete_picture
|
126
|
-
if !perform_delete_picture(
|
125
|
+
if !perform_delete_picture(entry.picture)
|
127
126
|
flash.alert = 'Could not delete picture'
|
128
127
|
false
|
129
128
|
end
|
@@ -135,7 +134,7 @@ In <tt>app/controllers/people_controller.rb</tt>:
|
|
135
134
|
before_render_form :set_hometowns
|
136
135
|
|
137
136
|
def set_hometowns
|
138
|
-
@hometowns = City.where(:country =>
|
137
|
+
@hometowns = City.where(:country => entry.country)
|
139
138
|
end
|
140
139
|
|
141
140
|
=== Standard Tables and Forms
|
@@ -181,6 +180,12 @@ Even +belongs_to+ associations are automatically rendered with a select field. B
|
|
181
180
|
|
182
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>:list</tt> option.
|
183
182
|
|
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>:list</tt> option:
|
184
|
+
<%= f.has_many_field :visited_cities, :list => City.where(:is_touristic => true) %>
|
185
|
+
|
186
|
+
And yes again, the same advice for where to put finder logic applies here as well.
|
187
|
+
|
188
|
+
<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/].
|
184
189
|
|
185
190
|
=== Nested Resources
|
186
191
|
|
@@ -188,7 +193,7 @@ In case you define nested resources, your +CrudController+ subclass should know.
|
|
188
193
|
|
189
194
|
self.nesting = :my_namspace, ParentResource
|
190
195
|
|
191
|
-
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.
|
196
|
+
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.
|
192
197
|
|
193
198
|
The <tt>ListController::Nesting</tt> module defines this basic behaviour. For more complex setups, have a look there and adjust it to your needs.
|
194
199
|
|
@@ -221,22 +226,22 @@ All generated files are supposed to provide a reasonable foundation for the CRUD
|
|
221
226
|
|
222
227
|
=== Controller:
|
223
228
|
|
224
|
-
{controller/crud_controller.rb}[http://codez.ch/dry_crud
|
229
|
+
{controller/crud_controller.rb}[http://codez.ch/dry_crud/CrudController.html]:: 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+.
|
225
230
|
|
226
|
-
{controller/list_controller.rb}[http://codez.ch/dry_crud
|
231
|
+
{controller/list_controller.rb}[http://codez.ch/dry_crud/ListController.html]:: Abstract controller providing a basic list action. Use this controller if you require read-only functionality. 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.
|
227
232
|
|
228
233
|
|
229
234
|
=== Helpers:
|
230
235
|
|
231
|
-
{helpers/standard_helper.rb}[http://codez.ch/dry_crud
|
236
|
+
{helpers/standard_helper.rb}[http://codez.ch/dry_crud/StandardHelper.html]:: 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+.
|
232
237
|
|
233
|
-
{helpers/crud_helper.rb}[http://codez.ch/dry_crud
|
238
|
+
{helpers/crud_helper.rb}[http://codez.ch/dry_crud/CrudHelper.html]:: A small helper for +CrudController+ to render tables and forms with a default set of attributes.
|
234
239
|
|
235
|
-
{helpers/list_helper.rb}[http://codez.ch/dry_crud
|
240
|
+
{helpers/list_helper.rb}[http://codez.ch/dry_crud/ListHelper.html]:: A small helper for +ListController+ to render the list table with a default set of attributes.
|
236
241
|
|
237
|
-
{helpers/standard_table_builder.rb}[http://codez.ch/dry_crud
|
242
|
+
{helpers/standard_table_builder.rb}[http://codez.ch/dry_crud/StandardTableBuilder.html]:: A simple helper object to easily define tables listing several rows of the same data type.
|
238
243
|
|
239
|
-
{helpers/standard_form_builder.rb}[http://codez.ch/dry_crud
|
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.
|
240
245
|
|
241
246
|
|
242
247
|
=== Views:
|
@@ -290,11 +295,11 @@ app/assets/images/action/*.png:: Some sample action icons from the {Open Icon Li
|
|
290
295
|
|
291
296
|
=== Tests:
|
292
297
|
|
293
|
-
{test/crud_test_model.rb}[http://codez.ch/dry_crud
|
298
|
+
{test/crud_test_model.rb}[http://codez.ch/dry_crud/CrudTestHelper.html]:: A dummy model to run CRUD tests against.
|
294
299
|
|
295
|
-
{test/custom_assertions.rb}[http://codez.ch/dry_crud
|
300
|
+
{test/custom_assertions.rb}[http://codez.ch/dry_crud/CustomAssertions.html]:: A handful of convenient assertions. Include this module into your <tt>test_helper.rb</tt> file.
|
296
301
|
|
297
|
-
{test/functionals/crud_controller_test_helper.rb}[http://codez.ch/dry_crud
|
302
|
+
{test/functionals/crud_controller_test_helper.rb}[http://codez.ch/dry_crud/CrudControllerTestHelper.html]:: 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.
|
298
303
|
|
299
304
|
test/several other tests:: Testing the provided implementation and a great base to test your adaptions of the CRUD code.
|
300
305
|
|
data/Rakefile
CHANGED
@@ -85,12 +85,12 @@ namespace :test do
|
|
85
85
|
desc "Adds pagination to the test app"
|
86
86
|
task :add_pagination => :generate_crud do
|
87
87
|
list_ctrl = File.join(TEST_APP_ROOT, 'app', 'controllers', 'list_controller.rb')
|
88
|
-
file_replace(list_ctrl,
|
89
|
-
"
|
88
|
+
file_replace(list_ctrl, /def list_entries\n\s+model_scope\s*\n/,
|
89
|
+
"def list_entries\n model_scope.page(params[:page]).per(10)\n")
|
90
90
|
file_replace(File.join(TEST_APP_ROOT, 'app', 'views', 'list', 'index.html.erb'),
|
91
|
-
"<%= render 'list' %>", "<%= paginate
|
91
|
+
"<%= render 'list' %>", "<%= paginate entries %>\n\n<%= render 'list' %>")
|
92
92
|
file_replace(File.join(TEST_APP_ROOT, 'app', 'views', 'list', 'index.html.haml'),
|
93
|
-
"= render 'list'", "= paginate
|
93
|
+
"= render 'list'", "= paginate entries\n\n= render 'list'")
|
94
94
|
end
|
95
95
|
|
96
96
|
desc "Use Boostrap in the test app"
|
@@ -98,6 +98,14 @@ namespace :test do
|
|
98
98
|
file_replace(File.join(TEST_APP_ROOT, 'app', 'assets', 'stylesheets', 'application.css'), " *= require_self", "*= require twitter/bootstrap\n *= require_self")
|
99
99
|
file_replace(File.join(TEST_APP_ROOT, 'app', 'assets', 'javascripts', 'application.js'), "//= require_tree .", "//= require twitter/bootstrap\n//= require_tree .")
|
100
100
|
FileUtils.rm(File.join(TEST_APP_ROOT, 'app', 'assets', 'stylesheets', 'sample.scss'))
|
101
|
+
|
102
|
+
layouts = File.join(TEST_APP_ROOT, 'app', 'views', 'layouts')
|
103
|
+
FileUtils.mv(File.join(layouts, 'bootstrap.html.erb'),
|
104
|
+
File.join(layouts, 'application.html.erb'),
|
105
|
+
:force => true) if File.exists?(File.join(layouts, 'bootstrap.html.erb'))
|
106
|
+
FileUtils.mv(File.join(layouts, 'bootstrap.html.haml'),
|
107
|
+
File.join(layouts, 'application.html.haml'),
|
108
|
+
:force => true) if File.exists?(File.join(layouts, 'bootstrap.html.haml'))
|
101
109
|
end
|
102
110
|
|
103
111
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.0
|
@@ -3,8 +3,8 @@ require 'rails/generators'
|
|
3
3
|
class DryCrudGenerator < Rails::Generators::Base
|
4
4
|
|
5
5
|
class_options %w(templates -t) => 'erb'
|
6
|
-
|
7
|
-
|
6
|
+
|
7
|
+
|
8
8
|
def self.source_root
|
9
9
|
File.join(File.dirname(__FILE__), 'templates')
|
10
10
|
end
|
@@ -12,13 +12,13 @@ class DryCrudGenerator < Rails::Generators::Base
|
|
12
12
|
def install_dry_crud
|
13
13
|
# copy everything in template subfolders
|
14
14
|
exclude = options[:templates].downcase == 'haml' ? '.erb' : '.haml'
|
15
|
-
|
15
|
+
|
16
16
|
Dir.chdir(self.class.source_root) do
|
17
17
|
Dir.glob(File.join('**', '**')).sort.each do |file_source|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
if !File.directory?(file_source) &&
|
19
|
+
!file_source.end_with?(exclude) &&
|
20
|
+
file_source != 'INSTALL'
|
21
|
+
copy_file(file_source)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
.labeled {
|
11
11
|
vertical-align: top;
|
12
|
-
padding
|
12
|
+
padding: 2px 0 2px;
|
13
13
|
clear: both;
|
14
14
|
}
|
15
15
|
|
@@ -27,14 +27,25 @@
|
|
27
27
|
margin: 0;
|
28
28
|
}
|
29
29
|
|
30
|
+
#content {
|
31
|
+
clear: both;
|
32
|
+
padding-top: 5px;
|
33
|
+
width: 100%;
|
34
|
+
}
|
35
|
+
|
36
|
+
table.table td.action {
|
37
|
+
width: 20px;
|
38
|
+
text-align: center;
|
39
|
+
}
|
40
|
+
|
30
41
|
.control-group {
|
31
42
|
clear: both;
|
43
|
+
padding: 2px 0 2px;
|
32
44
|
}
|
33
45
|
|
34
46
|
.control-group label {
|
35
47
|
float: left;
|
36
48
|
width: 120px;
|
37
|
-
padding-top: 5px;
|
38
49
|
padding-right: 5px;
|
39
50
|
}
|
40
51
|
|
@@ -42,6 +53,11 @@
|
|
42
53
|
margin-left: 130px;
|
43
54
|
}
|
44
55
|
|
56
|
+
.cancel {
|
57
|
+
font-size: 80%;
|
58
|
+
margin-left: 7px;
|
59
|
+
}
|
60
|
+
|
45
61
|
.required {
|
46
62
|
font-size: 80%;
|
47
63
|
vertical-align: top;
|
@@ -57,8 +73,3 @@
|
|
57
73
|
margin-bottom: 5px;
|
58
74
|
}
|
59
75
|
|
60
|
-
.controls div.field_with_errors {
|
61
|
-
background-color: #da9;
|
62
|
-
display: inline-block;
|
63
|
-
padding: 1px 1px;
|
64
|
-
}
|
@@ -25,11 +25,6 @@ body {
|
|
25
25
|
box-shadow: 0px 0px 5px $theme_color;
|
26
26
|
}
|
27
27
|
|
28
|
-
#content {
|
29
|
-
clear: both;
|
30
|
-
padding-top: 5px;
|
31
|
-
}
|
32
|
-
|
33
28
|
h1 {
|
34
29
|
font-size: 150%;
|
35
30
|
margin: 30px 0 15px 0;
|
@@ -102,13 +97,9 @@ table.table td {
|
|
102
97
|
padding: 2px 4px;
|
103
98
|
}
|
104
99
|
|
105
|
-
table.table td.action {
|
106
|
-
width: 20px;
|
107
|
-
text-align: center;
|
108
|
-
}
|
109
|
-
|
110
100
|
label {
|
111
101
|
font-style: italic;
|
102
|
+
text-align: right;
|
112
103
|
}
|
113
104
|
|
114
105
|
.form-actions {
|
@@ -155,16 +146,11 @@ input[type=number] {
|
|
155
146
|
width: 80px;
|
156
147
|
}
|
157
148
|
|
158
|
-
textarea {
|
149
|
+
textarea, select[multiple] {
|
159
150
|
width: 180px;
|
160
151
|
height: 80px;
|
161
152
|
}
|
162
153
|
|
163
|
-
.cancel {
|
164
|
-
font-size: 80%;
|
165
|
-
margin-left: 7px;
|
166
|
-
}
|
167
|
-
|
168
154
|
.alert {
|
169
155
|
margin: 15px;
|
170
156
|
padding: 5px 10px;
|
@@ -176,7 +162,7 @@ textarea {
|
|
176
162
|
}
|
177
163
|
|
178
164
|
.alert-error {
|
179
|
-
border: solid 2px #
|
165
|
+
border: solid 2px #D88;
|
180
166
|
background-color: #fec;
|
181
167
|
}
|
182
168
|
|
@@ -237,8 +223,9 @@ a.brand:hover {
|
|
237
223
|
display: block;
|
238
224
|
float: left;
|
239
225
|
margin: 0;
|
240
|
-
padding:
|
226
|
+
padding: 7px 12px 7px;
|
241
227
|
text-decoration: none;
|
228
|
+
height: 19px;
|
242
229
|
}
|
243
230
|
|
244
231
|
.nav a:hover {
|
@@ -255,4 +242,12 @@ footer {
|
|
255
242
|
|
256
243
|
footer * {
|
257
244
|
font-size: 80%;
|
245
|
+
}
|
246
|
+
|
247
|
+
.error .control-label {
|
248
|
+
color: #D88;
|
249
|
+
}
|
250
|
+
|
251
|
+
.error .controls input, .error .controls textarea {
|
252
|
+
border-color: #D88;
|
258
253
|
}
|
@@ -6,15 +6,8 @@
|
|
6
6
|
# overriding the entire method.
|
7
7
|
class CrudController < ListController
|
8
8
|
|
9
|
-
include ERB::Util
|
10
|
-
|
11
|
-
helper_method :entry, :full_entry_label
|
12
|
-
|
13
9
|
delegate :model_identifier, :to => 'self.class'
|
14
10
|
|
15
|
-
hide_action :model_identifier, :run_callbacks
|
16
|
-
|
17
|
-
|
18
11
|
# Defines before and after callback hooks for create, update, save and destroy actions.
|
19
12
|
define_model_callbacks :create, :update, :save, :destroy
|
20
13
|
|
@@ -22,70 +15,63 @@ class CrudController < ListController
|
|
22
15
|
# unifiying render_new and render_edit, called render_form, is defined further down.
|
23
16
|
define_render_callbacks :show, :new, :edit
|
24
17
|
|
18
|
+
after_save :set_success_notice
|
19
|
+
after_destroy :set_success_notice
|
20
|
+
|
21
|
+
helper_method :entry, :full_entry_label
|
22
|
+
|
23
|
+
hide_action :model_identifier, :run_callbacks
|
24
|
+
|
25
|
+
# Simple helper object to give access to required view helper methods.
|
26
|
+
@@helper = Object.new.extend(ActionView::Helpers::TranslationHelper).
|
27
|
+
extend(ActionView::Helpers::OutputSafetyHelper)
|
28
|
+
|
25
29
|
|
26
30
|
############## ACTIONS ############################################
|
27
31
|
|
28
32
|
# Show one entry of this model.
|
29
33
|
# GET /entries/1
|
30
34
|
# GET /entries/1.json
|
31
|
-
def show
|
32
|
-
respond_with
|
35
|
+
def show(&block)
|
36
|
+
respond_with(entry, &block)
|
33
37
|
end
|
34
38
|
|
35
39
|
# Display a form to create a new entry of this model.
|
36
40
|
# GET /entries/new
|
37
41
|
# GET /entries/new.json
|
38
|
-
def new
|
42
|
+
def new(&block)
|
39
43
|
assign_attributes
|
40
|
-
respond_with
|
44
|
+
respond_with(entry, &block)
|
41
45
|
end
|
42
46
|
|
43
47
|
# Create a new entry of this model from the passed params.
|
44
48
|
# There are before and after create callbacks to hook into the action.
|
45
49
|
# To customize the response, you may overwrite this action and call
|
46
|
-
# super with a block that gets
|
50
|
+
# super with a block that gets the format parameter.
|
47
51
|
# POST /entries
|
48
52
|
# POST /entries.json
|
49
53
|
def create(&block)
|
50
54
|
assign_attributes
|
51
55
|
created = with_callbacks(:create, :save) { entry.save }
|
52
|
-
|
53
|
-
customizable_respond_to(created, block) do |format|
|
54
|
-
if created
|
55
|
-
format.html { redirect_to_show success_notice }
|
56
|
-
format.json { render :json => entry, :status => :created, :location => path_args(entry) }
|
57
|
-
else
|
58
|
-
format.html { render_with_callback 'new' }
|
59
|
-
format.json { render :json => entry.errors, :status => :unprocessable_entity }
|
60
|
-
end
|
61
|
-
end
|
56
|
+
respond_with(entry, :success => created, &block)
|
62
57
|
end
|
63
58
|
|
64
59
|
# Display a form to edit an exisiting entry of this model.
|
65
60
|
# GET /entries/1/edit
|
66
|
-
def edit
|
67
|
-
|
61
|
+
def edit(&block)
|
62
|
+
respond_with(entry, &block)
|
68
63
|
end
|
69
64
|
|
70
65
|
# Update an existing entry of this model from the passed params.
|
71
66
|
# There are before and after update callbacks to hook into the action.
|
72
67
|
# To customize the response, you may overwrite this action and call
|
73
|
-
# super with a block that gets
|
68
|
+
# super with a block that gets the format parameter.
|
74
69
|
# PUT /entries/1
|
75
70
|
# PUT /entries/1.json
|
76
71
|
def update(&block)
|
77
72
|
assign_attributes
|
78
73
|
updated = with_callbacks(:update, :save) { entry.save }
|
79
|
-
|
80
|
-
customizable_respond_to(updated, block) do |format|
|
81
|
-
if updated
|
82
|
-
format.html { redirect_to_show success_notice }
|
83
|
-
format.json { head :ok }
|
84
|
-
else
|
85
|
-
format.html { render_with_callback 'edit' }
|
86
|
-
format.json { render :json => entry.errors, :status => :unprocessable_entity }
|
87
|
-
end
|
88
|
-
end
|
74
|
+
respond_with(entry, :success => updated, &block)
|
89
75
|
end
|
90
76
|
|
91
77
|
# Destroy an existing entry of this model.
|
@@ -96,19 +82,9 @@ class CrudController < ListController
|
|
96
82
|
# DELETE /entries/1.json
|
97
83
|
def destroy(&block)
|
98
84
|
destroyed = run_callbacks(:destroy) { entry.destroy }
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
format.html { redirect_to_index success_notice }
|
103
|
-
format.json { head :ok }
|
104
|
-
else
|
105
|
-
format.html {
|
106
|
-
flash.alert = entry.errors.full_messages.join('<br/>')
|
107
|
-
request.env["HTTP_REFERER"].present? ? redirect_to(:back) : redirect_to_show
|
108
|
-
}
|
109
|
-
format.json { render :json => entry.errors, :status => :unprocessable_entity }
|
110
|
-
end
|
111
|
-
end
|
85
|
+
flash[:alert] ||= error_messages.presence || flash_message(:failure) if !destroyed && request.format == :html
|
86
|
+
location = !destroyed && request.env["HTTP_REFERER"].presence || index_url
|
87
|
+
respond_with(entry, :success => destroyed, :location => location, &block)
|
112
88
|
end
|
113
89
|
|
114
90
|
protected
|
@@ -117,9 +93,9 @@ class CrudController < ListController
|
|
117
93
|
|
118
94
|
# Main accessor method for the handled model entry.
|
119
95
|
def entry
|
120
|
-
|
96
|
+
get_model_ivar || set_model_ivar(params[:id] ? find_entry : build_entry)
|
121
97
|
end
|
122
|
-
|
98
|
+
|
123
99
|
# Creates a new model entry.
|
124
100
|
def build_entry
|
125
101
|
model_scope.new
|
@@ -129,7 +105,7 @@ class CrudController < ListController
|
|
129
105
|
def find_entry
|
130
106
|
model_scope.find(params[:id])
|
131
107
|
end
|
132
|
-
|
108
|
+
|
133
109
|
# Assigns the attributes from the params to the model entry.
|
134
110
|
def assign_attributes
|
135
111
|
entry.attributes = params[model_identifier]
|
@@ -137,52 +113,39 @@ class CrudController < ListController
|
|
137
113
|
|
138
114
|
# A label for the current entry, including the model name.
|
139
115
|
def full_entry_label
|
140
|
-
"#{models_label(false)} <i>#{h(entry)}</i>".html_safe
|
116
|
+
"#{models_label(false)} <i>#{ERB::Util.h(entry)}</i>".html_safe
|
141
117
|
end
|
142
118
|
|
143
|
-
#
|
144
|
-
def
|
145
|
-
|
119
|
+
# Url of the index page to return to
|
120
|
+
def index_url
|
121
|
+
polymorphic_url(path_args(model_class), :returning => true)
|
146
122
|
end
|
147
123
|
|
148
|
-
|
149
|
-
def redirect_to_index(options = {})
|
150
|
-
redirect_to polymorphic_path(path_args(model_class), :returning => true), options
|
151
|
-
end
|
124
|
+
private
|
152
125
|
|
153
|
-
#
|
154
|
-
|
155
|
-
|
156
|
-
kinds.reverse.inject(block) do |b, kind|
|
157
|
-
lambda { run_callbacks(kind, &b) }
|
158
|
-
end.call
|
126
|
+
# Set a success flash notice when we got a HTML request.
|
127
|
+
def set_success_notice
|
128
|
+
flash[:notice] ||= flash_message(:success) if request.format == :html
|
159
129
|
end
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
#
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
yield format
|
173
|
-
end
|
130
|
+
|
131
|
+
# Get an I18n flash message, considering _html keys as well.
|
132
|
+
# Uses the key {controller_name}.{action_name}.flash.{state}
|
133
|
+
# or crud.{action_name}.flash.{state} as fallback.
|
134
|
+
def flash_message(state)
|
135
|
+
scope = "#{action_name}.flash.#{state}"
|
136
|
+
keys = [:"#{controller_name}.#{scope}_html",
|
137
|
+
:"#{controller_name}.#{scope}",
|
138
|
+
:"crud.#{scope}_html",
|
139
|
+
:"crud.#{scope}"]
|
140
|
+
@@helper.t(keys.shift, :model => full_entry_label, :default => keys)
|
174
141
|
end
|
175
142
|
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
def success_notice
|
180
|
-
key = "#{action_name}.flash.success"
|
181
|
-
{:notice => t(:"#{controller_name}.#{key}",
|
182
|
-
:model => full_entry_label,
|
183
|
-
:default => :"crud.#{key}")}
|
143
|
+
# Html safe error messages of the current entry.
|
144
|
+
def error_messages
|
145
|
+
@@helper.safe_join(entry.errors.full_messages, '<br/>'.html_safe)
|
184
146
|
end
|
185
147
|
|
148
|
+
|
186
149
|
class << self
|
187
150
|
# The identifier of the model used for form parameters.
|
188
151
|
# I.e., the symbol of the underscored model name.
|
@@ -197,4 +160,28 @@ class CrudController < ListController
|
|
197
160
|
end
|
198
161
|
end
|
199
162
|
|
163
|
+
# Custom Responder that handles the controller's path_args.
|
164
|
+
# An additional :success option is used to handle action callback chain halts.
|
165
|
+
class Responder < ActionController::Responder
|
166
|
+
|
167
|
+
def initialize(controller, resources, options = {})
|
168
|
+
super(controller, with_path_args(resources, controller), options)
|
169
|
+
end
|
170
|
+
|
171
|
+
protected
|
172
|
+
|
173
|
+
# Check whether the resource has errors. Additionally checks the :success option.
|
174
|
+
def has_errors?
|
175
|
+
options[:success] == false || super
|
176
|
+
end
|
177
|
+
|
178
|
+
# Wraps the resources with the path_args for correct nesting.
|
179
|
+
def with_path_args(resources, controller)
|
180
|
+
resources.size == 1 ? Array(controller.send(:path_args, resources.first)) : resources
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
self.responder = Responder
|
186
|
+
|
200
187
|
end
|