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
@@ -1,34 +1,25 @@
|
|
1
1
|
# Abstract controller providing a basic list action.
|
2
|
-
# This action lists all entries of a certain model and provides functionality to
|
3
|
-
# search and sort this list.
|
2
|
+
# This action lists all entries of a certain model and provides functionality to
|
3
|
+
# search and sort this list.
|
4
4
|
# Furthermore, it remembers the last search and sort parameters. When the action
|
5
5
|
# is called with a param returning=true, these parameters are reused to present
|
6
|
-
# the user the same list as he left it.
|
6
|
+
# the user the same list as he left it.
|
7
7
|
class ListController < ApplicationController
|
8
|
-
|
9
|
-
include RenderInheritable
|
10
|
-
|
8
|
+
|
9
|
+
include RenderInheritable
|
10
|
+
|
11
11
|
# Move this declaration to the application controller.
|
12
12
|
helper :standard
|
13
|
-
|
13
|
+
|
14
14
|
helper_method :model_class, :models_label
|
15
|
-
|
16
|
-
delegate :model_class, :models_label, :to => 'self.class'
|
17
|
-
|
15
|
+
|
16
|
+
delegate :model_class, :models_label, :to => 'self.class'
|
17
|
+
|
18
18
|
hide_action :model_class, :models_label, :inheritable_root_controller
|
19
|
-
|
20
|
-
|
21
|
-
# Callbacks
|
22
|
-
extend ActiveModel::Callbacks
|
23
|
-
|
24
|
-
# Defines before callbacks for the render actions.
|
25
|
-
define_model_callbacks :render_index,
|
26
|
-
:only => :before,
|
27
|
-
:terminator => "result == false || performed?"
|
28
|
-
|
29
|
-
|
19
|
+
|
20
|
+
|
30
21
|
############## ACTIONS ############################################
|
31
|
-
|
22
|
+
|
32
23
|
# List all entries of this model.
|
33
24
|
# GET /entries
|
34
25
|
# GET /entries.xml
|
@@ -36,15 +27,14 @@ class ListController < ApplicationController
|
|
36
27
|
@entries = list_entries
|
37
28
|
respond_with @entries
|
38
29
|
end
|
39
|
-
|
40
|
-
|
30
|
+
|
41
31
|
protected
|
42
|
-
|
32
|
+
|
43
33
|
# The entries to be displayed in the current index page.
|
44
34
|
def list_entries
|
45
35
|
model_class.scoped
|
46
|
-
end
|
47
|
-
|
36
|
+
end
|
37
|
+
|
48
38
|
# Convenience method to respond to various formats with the given object.
|
49
39
|
def respond_with(object)
|
50
40
|
respond_to do |format|
|
@@ -52,47 +42,61 @@ class ListController < ApplicationController
|
|
52
42
|
format.xml { render :xml => object }
|
53
43
|
end
|
54
44
|
end
|
55
|
-
|
45
|
+
|
56
46
|
# Helper method to run before_render callbacks and render the action.
|
57
47
|
# If a callback renders or redirects, the action is not rendered.
|
58
48
|
def render_with_callback(action)
|
59
49
|
run_callbacks(:"render_#{action}")
|
60
|
-
render
|
50
|
+
render action unless performed?
|
61
51
|
end
|
62
|
-
|
63
|
-
|
52
|
+
|
64
53
|
class << self
|
54
|
+
# Callbacks
|
55
|
+
include ActiveModel::Callbacks
|
56
|
+
|
65
57
|
# The ActiveRecord class of the model.
|
66
58
|
def model_class
|
67
59
|
@model_class ||= controller_name.classify.constantize
|
68
60
|
end
|
69
|
-
|
61
|
+
|
70
62
|
# A human readable plural name of the model.
|
71
|
-
def models_label
|
72
|
-
|
73
|
-
|
63
|
+
def models_label(plural = true)
|
64
|
+
opts = {:count => (plural ? 3 : 1)}
|
65
|
+
opts[:default] = model_class.model_name.human.pluralize if plural
|
66
|
+
model_class.model_name.human(opts)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Defines before callbacks for the render actions.
|
70
|
+
def define_render_callbacks(*actions)
|
71
|
+
args = actions.collect {|a| :"render_#{a}" }
|
72
|
+
args << {:only => :before,
|
73
|
+
:terminator => "result == false || performed?"}
|
74
|
+
define_model_callbacks *args
|
75
|
+
end
|
74
76
|
end
|
75
77
|
|
78
|
+
define_render_callbacks :index
|
79
|
+
|
76
80
|
# The search functionality for the index table.
|
77
81
|
# Extracted into an own module for convenience.
|
78
82
|
module Search
|
79
|
-
def self.included(controller)
|
83
|
+
def self.included(controller)
|
80
84
|
# Define an array of searchable columns in your subclassing controllers.
|
81
85
|
controller.class_attribute :search_columns
|
82
86
|
controller.search_columns = []
|
83
|
-
|
87
|
+
|
84
88
|
controller.helper_method :search_support?
|
85
|
-
|
89
|
+
|
86
90
|
controller.alias_method_chain :list_entries, :search
|
87
91
|
end
|
88
|
-
|
92
|
+
|
89
93
|
protected
|
90
|
-
|
94
|
+
|
91
95
|
# Enhance the list entries with an optional search criteria
|
92
96
|
def list_entries_with_search
|
93
97
|
list_entries_without_search.where(search_condition)
|
94
98
|
end
|
95
|
-
|
99
|
+
|
96
100
|
# Compose the search condition with a basic SQL OR query.
|
97
101
|
def search_condition
|
98
102
|
if search_support? && params[:q].present?
|
@@ -102,16 +106,16 @@ class ListController < ApplicationController
|
|
102
106
|
["(#{clause})"] + [param] * search_columns.size
|
103
107
|
end
|
104
108
|
end
|
105
|
-
|
109
|
+
|
106
110
|
# Returns true if this controller has searchable columns.
|
107
111
|
def search_support?
|
108
112
|
search_columns.present?
|
109
113
|
end
|
110
|
-
|
114
|
+
|
111
115
|
end
|
112
|
-
|
116
|
+
|
113
117
|
include Search
|
114
|
-
|
118
|
+
|
115
119
|
# Sort functionality for the index table.
|
116
120
|
# Extracted into an own module for convenience.
|
117
121
|
module Sort
|
@@ -123,14 +127,14 @@ class ListController < ApplicationController
|
|
123
127
|
# sort the displayed city names.
|
124
128
|
controller.class_attribute :sort_mappings
|
125
129
|
controller.sort_mappings = {}
|
126
|
-
|
130
|
+
|
127
131
|
controller.helper_method :sortable?
|
128
|
-
|
132
|
+
|
129
133
|
controller.alias_method_chain :list_entries, :sort
|
130
134
|
end
|
131
|
-
|
135
|
+
|
132
136
|
protected
|
133
|
-
|
137
|
+
|
134
138
|
# Enhance the list entries with an optional sort order.
|
135
139
|
def list_entries_with_sort
|
136
140
|
if params[:sort].present? && sortable?(params[:sort])
|
@@ -139,73 +143,85 @@ class ListController < ApplicationController
|
|
139
143
|
list_entries_without_sort
|
140
144
|
end
|
141
145
|
end
|
142
|
-
|
146
|
+
|
143
147
|
# Return the sort expression to be used in the list query.
|
144
148
|
def sort_expression
|
145
|
-
col = sort_mappings[params[:sort].to_sym] ||
|
149
|
+
col = sort_mappings[params[:sort].to_sym] ||
|
146
150
|
"#{model_class.table_name}.#{params[:sort]}"
|
147
151
|
"#{col} #{sort_dir}"
|
148
152
|
end
|
149
|
-
|
153
|
+
|
150
154
|
# The sort direction, either 'asc' or 'desc'.
|
151
155
|
def sort_dir
|
152
156
|
params[:sort_dir] == 'desc' ? 'desc' : 'asc'
|
153
157
|
end
|
154
|
-
|
158
|
+
|
155
159
|
# Returns true if the passed attribute is sortable.
|
156
160
|
def sortable?(attr)
|
157
|
-
model_class.column_names.include?(attr.to_s) ||
|
161
|
+
model_class.column_names.include?(attr.to_s) ||
|
158
162
|
sort_mappings.include?(attr.to_sym)
|
159
163
|
end
|
160
164
|
end
|
161
|
-
|
165
|
+
|
162
166
|
include Sort
|
163
|
-
|
167
|
+
|
164
168
|
# Remembers certain params of the index action in order to return
|
165
169
|
# to the same list after an entry was viewed or edited.
|
166
170
|
# If the index is called with a param :returning, the remembered params
|
167
171
|
# will be re-used.
|
168
172
|
# Extracted into an own module for convenience.
|
169
173
|
module Memory
|
170
|
-
|
174
|
+
|
171
175
|
# Adds the :remember_params class attribute and a before filter to the index action.
|
172
|
-
def self.included(controller)
|
176
|
+
def self.included(controller)
|
173
177
|
# Define a list of param keys that should be remembered for the list action.
|
174
178
|
controller.class_attribute :remember_params
|
175
179
|
controller.remember_params = [:q, :sort, :sort_dir]
|
176
|
-
|
180
|
+
|
177
181
|
controller.before_filter :handle_remember_params, :only => [:index]
|
178
182
|
end
|
179
|
-
|
183
|
+
|
180
184
|
private
|
181
|
-
|
185
|
+
|
182
186
|
# Store and restore the corresponding params.
|
183
187
|
def handle_remember_params
|
184
188
|
remembered = remembered_params
|
189
|
+
|
190
|
+
restore_params_on_return(remembered)
|
191
|
+
store_current_params(remembered)
|
192
|
+
clear_void_params(remembered)
|
193
|
+
end
|
194
|
+
|
195
|
+
def restore_params_on_return(remembered)
|
185
196
|
if params[:returning]
|
186
|
-
# restore params
|
187
197
|
remember_params.each {|p| params[p] ||= remembered[p] }
|
188
198
|
end
|
189
|
-
|
190
|
-
|
191
|
-
|
199
|
+
end
|
200
|
+
|
201
|
+
def store_current_params(remembered)
|
202
|
+
remember_params.each do |p|
|
192
203
|
remembered[p] = params[p].presence
|
193
204
|
remembered.delete(p) if remembered[p].nil?
|
194
205
|
end
|
195
|
-
|
196
|
-
# clear void params
|
197
|
-
session[:list_params].delete(request.path) if remembered.blank?
|
198
206
|
end
|
199
|
-
|
207
|
+
|
208
|
+
def clear_void_params(remembered)
|
209
|
+
session[:list_params].delete(remember_key) if remembered.blank?
|
210
|
+
end
|
211
|
+
|
200
212
|
# Get the params stored in the session.
|
201
|
-
# Params are stored by request path to play nice when a controller
|
202
|
-
# is used in different routes.
|
203
213
|
def remembered_params
|
204
214
|
session[:list_params] ||= {}
|
205
|
-
session[:list_params][
|
215
|
+
session[:list_params][remember_key] ||= {}
|
216
|
+
end
|
217
|
+
|
218
|
+
# Params are stored by request path to play nice when a controller
|
219
|
+
# is used in different routes.
|
220
|
+
def remember_key
|
221
|
+
request.path
|
206
222
|
end
|
207
223
|
end
|
208
|
-
|
224
|
+
|
209
225
|
include Memory
|
210
|
-
|
226
|
+
|
211
227
|
end
|
@@ -2,55 +2,56 @@
|
|
2
2
|
# If no view file is found for the current controller, the corresponding file
|
3
3
|
# is looked up in its superclass hierarchy. This module must only be
|
4
4
|
# included in the root controller of the desired lookup hierarchy.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# By default, this module only supports direct inheritance over one level. By overriding
|
7
7
|
# the method lookup_path, you may define a custom lookup path. By providing an object
|
8
8
|
# for the 'with' parameter, this path may even be dynamic.
|
9
9
|
module RenderInheritable
|
10
|
-
|
10
|
+
|
11
11
|
# Add inheritable_root_path method to including controller.
|
12
12
|
def self.included(controller_class)
|
13
13
|
controller_class.send(:extend, ClassMethods)
|
14
|
-
|
14
|
+
|
15
15
|
controller_class.send(:class_variable_set, :@@inheritable_root_controller, controller_class)
|
16
16
|
controller_class.cattr_reader :inheritable_root_controller
|
17
|
-
end
|
18
|
-
|
17
|
+
end
|
18
|
+
|
19
19
|
# Performs a lookup for the given filename and returns the most specific
|
20
20
|
# folder that contains the file.
|
21
21
|
def find_inheritable_template_folder(name, partial = false)
|
22
22
|
self.class.find_inheritable_template_folder(view_context, name, partial, formats, template_lookup_param)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
# Override this method to specify a dynamic parameter used in the lookup path.
|
26
26
|
# For the default inheritance lookup, this parameter is not needed.
|
27
27
|
def template_lookup_param
|
28
28
|
nil
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
module ClassMethods
|
32
|
+
|
32
33
|
# Performs a lookup for the given filename and returns the most specific
|
33
34
|
# folder that contains the file.
|
34
|
-
def find_inheritable_template_folder(view_context, name, partial, formats, param = nil)
|
35
|
+
def find_inheritable_template_folder(view_context, name, partial, formats, param = nil)
|
35
36
|
find_inheritable_template_folder_cached(view_context, name, partial, formats, param) do
|
36
37
|
find_inheritable_artifact(param) do |folder|
|
37
38
|
view_context.template_exists?(name, folder, partial)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
41
|
-
|
42
|
+
|
42
43
|
# Performs a lookup for a controller and returns the name of the most specific one found.
|
43
44
|
# This method is primarly usefull when given a 'param' argument that is used
|
44
|
-
# in a custom #template_lookup_path. In this case, no controller class would need to
|
45
|
+
# in a custom #template_lookup_path. In this case, no controller class would need to
|
45
46
|
# exist to render templates from corresponding view folders.
|
46
47
|
def inheritable_controller(param = nil)
|
47
48
|
descendants = inheritable_root_controller.descendants
|
48
49
|
c = find_inheritable_artifact(param) do |folder|
|
49
|
-
|
50
|
+
descendants.any? { |s| s.controller_path == folder }
|
50
51
|
end
|
51
52
|
c || inheritable_root_controller.controller_path
|
52
53
|
end
|
53
|
-
|
54
|
+
|
54
55
|
# Runs through the lookup path and yields each folder to the passed block.
|
55
56
|
# If the block returns true, this folder is returned and no further lookup
|
56
57
|
# happens. If no folder is found, the nil is returned.
|
@@ -58,14 +59,14 @@ module RenderInheritable
|
|
58
59
|
template_lookup_path(param).each { |folder| return folder if yield(folder) }
|
59
60
|
nil
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
# An array of controller names / folders, ordered from most specific to most general.
|
63
|
-
# May be dynamic dependening on the passed 'param' argument.
|
64
|
+
# May be dynamic dependening on the passed 'param' argument.
|
64
65
|
# You may override this method in an own controller to customize the lookup path.
|
65
66
|
def template_lookup_path(param = nil)
|
66
67
|
inheritance_lookup_path
|
67
68
|
end
|
68
|
-
|
69
|
+
|
69
70
|
# The inheritance path of controllers that is used as default lookup path.
|
70
71
|
def inheritance_lookup_path
|
71
72
|
path = [self]
|
@@ -74,8 +75,8 @@ module RenderInheritable
|
|
74
75
|
end
|
75
76
|
path.collect(&:controller_path)
|
76
77
|
end
|
77
|
-
|
78
|
-
# Override view context class to
|
78
|
+
|
79
|
+
# Override view context class to include the render inheritable modules.
|
79
80
|
def view_context_class
|
80
81
|
@view_context_class ||= begin
|
81
82
|
Class.new(super) do
|
@@ -83,46 +84,46 @@ module RenderInheritable
|
|
83
84
|
end
|
84
85
|
end
|
85
86
|
end
|
86
|
-
|
87
|
+
|
87
88
|
private
|
88
|
-
|
89
|
+
|
89
90
|
# Performs a lookup for a template folder using the cache.
|
90
91
|
def find_inheritable_template_folder_cached(view_context, name, partial, formats, param = nil)
|
91
92
|
prefix = inheritable_cache_get(formats, name, partial, param)
|
92
93
|
return prefix if prefix
|
93
|
-
|
94
|
+
|
94
95
|
prefix = yield
|
95
|
-
|
96
|
+
|
96
97
|
if prefix
|
97
98
|
template = view_context.find_template_without_lookup(name, prefix, partial)
|
98
99
|
inheritable_cache_set(template.formats, name, partial, param, prefix)
|
99
100
|
end
|
100
101
|
prefix
|
101
102
|
end
|
102
|
-
|
103
|
+
|
103
104
|
# A simple template lookup cache for each controller.
|
104
105
|
def inheritable_cache #:nodoc:
|
105
106
|
# do not store keys on each access, only return default structure
|
106
|
-
@inheritable_cache ||= Hash.new do |h1, k1|
|
107
|
-
Hash.new do |h2, k2|
|
108
|
-
Hash.new do |h3, k3|
|
109
|
-
Hash.new
|
107
|
+
@inheritable_cache ||= Hash.new do |h1, k1|
|
108
|
+
Hash.new do |h2, k2|
|
109
|
+
Hash.new do |h3, k3|
|
110
|
+
Hash.new
|
110
111
|
end
|
111
112
|
end
|
112
113
|
end
|
113
114
|
end
|
114
|
-
|
115
|
+
|
115
116
|
# Gets the prefix from the cache. Returns nil if it's not there yet.
|
116
117
|
def inheritable_cache_get(formats, name, partial, param)
|
117
118
|
prefixes = formats.collect { |format| inheritable_cache[format.to_sym][partial][name][param] }
|
118
119
|
prefixes.compact!
|
119
120
|
prefixes.empty? ? nil : prefixes.first
|
120
121
|
end
|
121
|
-
|
122
|
+
|
122
123
|
# Stores the found prefix in the cache.
|
123
124
|
def inheritable_cache_set(formats, name, partial, param, prefix)
|
124
125
|
formats.each do |format|
|
125
|
-
# assign hash default values to respective key
|
126
|
+
# assign hash default values to respective key
|
126
127
|
inheritable_cache[format.to_sym] = hf = inheritable_cache[format.to_sym]
|
127
128
|
hf[partial] = hp = hf[partial]
|
128
129
|
hp[name] = hn = hp[name]
|
@@ -130,15 +131,15 @@ module RenderInheritable
|
|
130
131
|
hn[param] = prefix
|
131
132
|
end
|
132
133
|
end
|
133
|
-
|
134
|
+
|
134
135
|
end
|
135
|
-
|
136
|
+
|
136
137
|
# Extend ActionView so templates are looked up on a find_template call.
|
137
138
|
module View
|
138
139
|
def self.included(base)
|
139
140
|
base.send :alias_method_chain, :find_template, :lookup
|
140
141
|
end
|
141
|
-
|
142
|
+
|
142
143
|
# Perform a template lookup if the prefix corresponds to the current controller's path.
|
143
144
|
def find_template_with_lookup(name, prefix = nil, partial = false)
|
144
145
|
if prefix == controller_path
|
@@ -148,5 +149,5 @@ module RenderInheritable
|
|
148
149
|
find_template_without_lookup(name, prefix, partial)
|
149
150
|
end
|
150
151
|
end
|
151
|
-
|
152
|
+
|
152
153
|
end
|