dry_crud 3.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +1 -1
  3. data/VERSION +1 -1
  4. data/app/controllers/crud_controller.rb +10 -8
  5. data/app/controllers/dry_crud/generic_model.rb +6 -4
  6. data/app/controllers/dry_crud/nestable.rb +9 -11
  7. data/app/controllers/dry_crud/rememberable.rb +5 -1
  8. data/app/controllers/dry_crud/render_callbacks.rb +40 -19
  9. data/app/controllers/dry_crud/searchable.rb +40 -31
  10. data/app/controllers/dry_crud/sortable.rb +36 -26
  11. data/app/controllers/list_controller.rb +2 -2
  12. data/app/helpers/dry_crud/form/builder.rb +21 -13
  13. data/app/helpers/dry_crud/form/control.rb +8 -9
  14. data/app/helpers/dry_crud/table/actions.rb +6 -1
  15. data/app/helpers/dry_crud/table/builder.rb +4 -2
  16. data/app/helpers/dry_crud/table/col.rb +12 -1
  17. data/app/helpers/dry_crud/table/sorting.rb +7 -1
  18. data/app/helpers/form_helper.rb +7 -7
  19. data/app/helpers/format_helper.rb +3 -3
  20. data/app/helpers/i18n_helper.rb +3 -3
  21. data/app/helpers/utility_helper.rb +4 -1
  22. data/lib/dry_crud.rb +1 -2
  23. data/lib/dry_crud/engine.rb +5 -7
  24. data/lib/generators/dry_crud/dry_crud_generator.rb +3 -4
  25. data/lib/generators/dry_crud/dry_crud_generator_base.rb +6 -8
  26. data/lib/generators/dry_crud/file_generator.rb +1 -3
  27. data/lib/generators/dry_crud/templates/spec/controllers/crud_test_models_controller_spec.rb +8 -18
  28. data/lib/generators/dry_crud/templates/spec/helpers/form_helper_spec.rb +1 -1
  29. data/lib/generators/dry_crud/templates/spec/helpers/utility_helper_spec.rb +4 -4
  30. data/lib/generators/dry_crud/templates/spec/support/crud_controller_examples.rb +7 -17
  31. data/lib/generators/dry_crud/templates/spec/support/crud_controller_test_helper.rb +13 -29
  32. data/lib/generators/dry_crud/templates/test/controllers/crud_test_models_controller_test.rb +25 -44
  33. data/lib/generators/dry_crud/templates/test/helpers/custom_assertions_test.rb +0 -1
  34. data/lib/generators/dry_crud/templates/test/helpers/dry_crud/form/builder_test.rb +3 -4
  35. data/lib/generators/dry_crud/templates/test/helpers/dry_crud/table/builder_test.rb +0 -2
  36. data/lib/generators/dry_crud/templates/test/helpers/form_helper_test.rb +2 -1
  37. data/lib/generators/dry_crud/templates/test/helpers/format_helper_test.rb +1 -1
  38. data/lib/generators/dry_crud/templates/test/helpers/table_helper_test.rb +8 -17
  39. data/lib/generators/dry_crud/templates/test/helpers/utility_helper_test.rb +3 -0
  40. data/lib/generators/dry_crud/templates/test/support/crud_controller_test_helper.rb +27 -30
  41. data/lib/generators/dry_crud/templates/test/support/crud_test_helper.rb +11 -13
  42. data/lib/generators/dry_crud/templates/test/support/crud_test_model.rb +7 -3
  43. data/lib/generators/dry_crud/templates/test/support/crud_test_models_controller.rb +5 -9
  44. data/lib/generators/dry_crud/templates/test/support/custom_assertions.rb +1 -1
  45. metadata +10 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 664cf77c042838728de2d0abb74525808c496448
4
- data.tar.gz: e12c82079d72d2f414cef3181d2fcd14e9f72552
3
+ metadata.gz: cd475eb483f54acdff9dff23ae75d80715edfcdb
4
+ data.tar.gz: 7ba54fb2d5a22f562627fd0641f23e2a32a975ee
5
5
  SHA512:
6
- metadata.gz: fb4bd2d805c8bc9a0dfa4a3eb3cf25758d70abcde034b9380d6e181bb1a8918420be98c326d036926d30c92b56fe0a7d02d5232e30a0a72b704cc02d2c9fa660
7
- data.tar.gz: 5851c097e6904e68f7abaec88d5c0bec6c651de07e482737f667dd7832f976a9bb5b390900669910e945e5fc33afae27359735f1ae3c2420f7f0309902135821
6
+ metadata.gz: 38e784965cdb8dc622b659437fa6cb2e4be27eb3eb17b3c1686a5ec6cdfded184fb08fb10a533ff6d7f9e14331045b111aadbde8a371d6c59272462c589839e6
7
+ data.tar.gz: e0b78f3534243dd715cb53c6ddbfc547f236e90e84ee6a7439e392a4d0b837f17fd2a7e9e5a24fb1b885611aaf44f7c2dca47ac388256279559cd5b212e24699
@@ -33,7 +33,7 @@ To integrate dry_crud into your code, only a few additions are required:
33
33
  * Optionally define a +list+ scope in your models to be used in the +index+ action.
34
34
  * Optionally define a +options_list+ scope in your models to be used in select dropdowns.
35
35
 
36
- From version 3.0, only the latest released Rails version will be supported, which currently is 4.2. Version 2.0 and higher are compatible with Rails 4 and Rails 3.2. dry_crud is tested with Ruby 1.9.3, 2.1.5 and JRuby. If you are using Ruby 1.8.7, please refer to version 1.7.0.
36
+ From version 5.0 onwards, the major and minor version numbers will be kept in sync with Rails, and only the matching Rails version is supported. Version 3.0 is compatible 4.2, Version 2.0 and higher are compatible with Rails 4 and Rails 3.2. dry_crud is tested with Ruby 2.2.5 and JRuby. If you are using Ruby 1.9.3, please refer to version 3.0.0.
37
37
 
38
38
 
39
39
  == Background
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 5.0.0
@@ -22,8 +22,6 @@ class CrudController < ListController
22
22
  # further down.
23
23
  define_render_callbacks :show, :new, :edit
24
24
 
25
- hide_action :run_callbacks
26
-
27
25
  before_action :entry, only: [:show, :new, :edit, :update, :destroy]
28
26
 
29
27
  helper_method :entry, :full_entry_label
@@ -57,12 +55,12 @@ class CrudController < ListController
57
55
  # in the given block will take precedence over the one defined here.
58
56
  #
59
57
  # Specify a :location option if you wish to do a custom redirect.
60
- def create(options = {}, &block)
58
+ def create(options = {}, &_block)
61
59
  assign_attributes
62
60
  created = with_callbacks(:create, :save) { entry.save }
63
61
 
64
62
  respond_to do |format|
65
- block.call(format, created) if block_given?
63
+ yield(format, created) if block_given?
66
64
  if created
67
65
  format.html { redirect_on_success(options) }
68
66
  format.json { render :show, status: :created, location: show_path }
@@ -91,12 +89,12 @@ class CrudController < ListController
91
89
  # in the given block will take precedence over the one defined here.
92
90
  #
93
91
  # Specify a :location option if you wish to do a custom redirect.
94
- def update(options = {}, &block)
92
+ def update(options = {}, &_block)
95
93
  assign_attributes
96
94
  updated = with_callbacks(:update, :save) { entry.save }
97
95
 
98
96
  respond_to do |format|
99
- block.call(format, updated) if block_given?
97
+ yield(format, updated) if block_given?
100
98
  if updated
101
99
  format.html { redirect_on_success(options) }
102
100
  format.json { render :show, status: :ok, location: show_path }
@@ -119,11 +117,11 @@ class CrudController < ListController
119
117
  # in the given block will take precedence over the one defined here.
120
118
  #
121
119
  # Specify a :location option if you wish to do a custom redirect.
122
- def destroy(options = {}, &block)
120
+ def destroy(options = {}, &_block)
123
121
  destroyed = run_callbacks(:destroy) { entry.destroy }
124
122
 
125
123
  respond_to do |format|
126
- block.call(format, destroyed) if block_given?
124
+ yield(format, destroyed) if block_given?
127
125
  if destroyed
128
126
  format.html { redirect_on_success(options) }
129
127
  format.json { head :no_content }
@@ -204,13 +202,17 @@ class CrudController < ListController
204
202
 
205
203
  # A label for the current entry, including the model name.
206
204
  def full_entry_label
205
+ # rubocop:disable Rails/OutputSafety
207
206
  "#{models_label(false)} <i>#{ERB::Util.h(entry)}</i>".html_safe
207
+ # rubocop:enable Rails/OutputSafety
208
208
  end
209
209
 
210
210
  # Html safe error messages of the current entry.
211
211
  def error_messages
212
+ # rubocop:disable Rails/OutputSafety
212
213
  escaped = entry.errors.full_messages.map { |m| ERB::Util.html_escape(m) }
213
214
  escaped.join('<br/>').html_safe
215
+ # rubocop:enable Rails/OutputSafety
214
216
  end
215
217
 
216
218
  # Class methods for CrudActions.
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module DryCrud
4
+
4
5
  # Connects the including controller to the model whose name corrsponds to
5
6
  # the controller's name.
6
7
  #
@@ -8,6 +9,7 @@ module DryCrud
8
9
  # Additional helper methods store and retrieve values in instance variables
9
10
  # named after their class.
10
11
  module GenericModel
12
+
11
13
  extend ActiveSupport::Concern
12
14
 
13
15
  included do
@@ -18,8 +20,6 @@ module DryCrud
18
20
  delegate :model_class, :models_label, :model_identifier, to: 'self.class'
19
21
  end
20
22
 
21
- private
22
-
23
23
  # The scope where model entries will be listed and created.
24
24
  # This is mainly used for nested models to provide the
25
25
  # required context.
@@ -38,7 +38,8 @@ module DryCrud
38
38
  def model_ivar_get(plural = false)
39
39
  name = ivar_name(model_class)
40
40
  name = name.pluralize if plural
41
- instance_variable_get(:"@#{name}")
41
+ name = :"@#{name}"
42
+ instance_variable_get(name) if instance_variable_defined?(name)
42
43
  end
43
44
 
44
45
  # Sets an instance variable with the underscored class name if the given
@@ -60,6 +61,7 @@ module DryCrud
60
61
 
61
62
  # Class methods from GenericModel.
62
63
  module ClassMethods
64
+
63
65
  # The ActiveRecord class of the model.
64
66
  def model_class
65
67
  @model_class ||= controller_name.classify.constantize
@@ -79,7 +81,7 @@ module DryCrud
79
81
 
80
82
  model_class.model_name.human(opts)
81
83
  end
82
- end
83
84
 
85
+ end
84
86
  end
85
87
  end
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module DryCrud
4
+
4
5
  # Provides functionality to nest controllers/resources.
5
6
  # If a controller is nested, the parent classes and namespaces
6
7
  # may be defined as an array in the +nesting+ class attribute.
@@ -9,24 +10,20 @@ module DryCrud
9
10
  # namespace, may define this attribute as follows:
10
11
  # self.nesting = :admin, Country
11
12
  module Nestable
12
- extend ActiveSupport::Concern
13
13
 
14
14
  # Adds the :nesting class attribute and parent helper methods
15
15
  # to the including controller.
16
- included do
17
- class_attribute :nesting
18
-
19
- helper_method :parent, :parents
16
+ def self.prepended(klass)
17
+ klass.class_attribute :nesting
20
18
 
21
- alias_method_chain :path_args, :nesting
22
- alias_method_chain :model_scope, :nesting
19
+ klass.helper_method :parent, :parents
23
20
  end
24
21
 
25
22
  private
26
23
 
27
24
  # Returns the direct parent ActiveRecord of the current request, if any.
28
25
  def parent
29
- parents.select { |p| p.is_a?(ActiveRecord::Base) }.last
26
+ parents.reverse.find { |p| p.is_a?(ActiveRecord::Base) }
30
27
  end
31
28
 
32
29
  # Returns the parent entries of the current request, if any.
@@ -49,16 +46,16 @@ module DryCrud
49
46
  end
50
47
 
51
48
  # An array of objects used in url_for and related functions.
52
- def path_args_with_nesting(last)
49
+ def path_args(last)
53
50
  parents + [last]
54
51
  end
55
52
 
56
53
  # Uses the parent entry (if any) to constrain the model scope.
57
- def model_scope_with_nesting
54
+ def model_scope
58
55
  if parent.present?
59
56
  parent_scope
60
57
  else
61
- model_scope_without_nesting
58
+ super
62
59
  end
63
60
  end
64
61
 
@@ -66,5 +63,6 @@ module DryCrud
66
63
  def parent_scope
67
64
  parent.send(model_class.name.underscore.pluralize)
68
65
  end
66
+
69
67
  end
70
68
  end
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module DryCrud
4
+
4
5
  # Remembers certain params of the index action in order to return
5
6
  # to the same list after an entry was viewed or edited.
6
7
  # If the index is called with a param :returning, the remembered params
@@ -12,13 +13,14 @@ module DryCrud
12
13
  # The params are stored separately for each different +remember_key+, which
13
14
  # defaults to the current request's path.
14
15
  module Rememberable
16
+
15
17
  extend ActiveSupport::Concern
16
18
 
17
19
  included do
18
20
  class_attribute :remember_params
19
21
  self.remember_params = %w(q sort sort_dir page)
20
22
 
21
- before_filter :handle_remember_params, only: [:index]
23
+ before_action :handle_remember_params, only: [:index]
22
24
  end
23
25
 
24
26
  private
@@ -53,6 +55,7 @@ module DryCrud
53
55
  def remembered_params
54
56
  session[:list_params] ||= {}
55
57
  session[:list_params][remember_key] ||= {}
58
+ session[:list_params][remember_key]
56
59
  end
57
60
 
58
61
  # Params are stored by request path to play nice when a controller
@@ -60,5 +63,6 @@ module DryCrud
60
63
  def remember_key
61
64
  request.path
62
65
  end
66
+
63
67
  end
64
68
  end
@@ -1,46 +1,67 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module DryCrud
4
+
4
5
  # Provide +before_render+ callbacks.
5
6
  module RenderCallbacks
7
+
6
8
  extend ActiveSupport::Concern
7
9
 
8
10
  included do
9
11
  extend ActiveModel::Callbacks
10
-
11
- alias_method_chain :render, :callbacks
12
+ prepend Prepends
12
13
  end
13
14
 
14
- # Helper method to run +before_render+ callbacks and render the action.
15
- # If a callback renders or redirects, the action is not rendered.
16
- def render_with_callbacks(*args, &block)
17
- options = _normalize_render(*args, &block)
18
- callback = "render_#{options[:template]}"
15
+ # Prepended methods for callbacks.
16
+ module Prepends
19
17
 
20
- run_callbacks(callback) if respond_to?(:"_#{callback}_callbacks", true)
18
+ # Helper method to run +before_render+ callbacks and render the action.
19
+ # If a callback renders or redirects, the action is not rendered.
20
+ def render(*args, &block)
21
+ options = _normalize_render(*args, &block)
22
+ callback = "render_#{options[:template]}"
21
23
 
22
- render_without_callbacks(*args, &block) unless performed?
23
- end
24
+ run_callbacks(callback) if respond_to?(:"_#{callback}_callbacks", true)
25
+
26
+ super(*args, &block) unless performed?
27
+ end
28
+
29
+ private
24
30
 
25
- private
31
+ # Helper method the run the given block in between the before and after
32
+ # callbacks of the given kinds.
33
+ def with_callbacks(*kinds, &block)
34
+ kinds.reverse.reduce(block) do |a, e|
35
+ -> { run_callbacks(e, &a) }
36
+ end.call
37
+ end
26
38
 
27
- # Helper method the run the given block in between the before and after
28
- # callbacks of the given kinds.
29
- def with_callbacks(*kinds, &block)
30
- kinds.reverse.reduce(block) do |a, e|
31
- -> { run_callbacks(e, &a) }
32
- end.call
33
39
  end
34
40
 
35
41
  # Class methods for callbacks.
36
42
  module ClassMethods
43
+
37
44
  # Defines before callbacks for the render actions.
38
45
  def define_render_callbacks(*actions)
39
46
  args = actions.map { |a| :"render_#{a}" }
40
- terminator = ->(ctrl, result) { result == false || ctrl.performed? }
41
- args << { only: :before, terminator: terminator }
47
+ args << { only: :before, terminator: render_callback_terminator }
42
48
  define_model_callbacks(*args)
43
49
  end
50
+
51
+ private
52
+
53
+ def render_callback_terminator
54
+ proc do |ctrl, result_lambda|
55
+ terminate = true
56
+ catch(:abort) do
57
+ result_lambda.call if result_lambda.is_a?(Proc)
58
+ terminate = !ctrl.response_body.nil?
59
+ end
60
+ terminate
61
+ end
62
+ end
63
+
44
64
  end
65
+
45
66
  end
46
67
  end
@@ -1,10 +1,12 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module DryCrud
4
+
4
5
  # The search functionality for the index table.
5
6
  # Define an array of searchable string columns in your subclassing
6
7
  # controllers using the class attribute +search_columns+.
7
8
  module Searchable
9
+
8
10
  extend ActiveSupport::Concern
9
11
 
10
12
  included do
@@ -13,49 +15,55 @@ module DryCrud
13
15
 
14
16
  helper_method :search_support?
15
17
 
16
- alias_method_chain :list_entries, :search
18
+ prepend Prepends
17
19
  end
18
20
 
19
- private
21
+ # Prepended methods for searching.
22
+ module Prepends
20
23
 
21
- # Enhance the list entries with an optional search criteria
22
- def list_entries_with_search
23
- list_entries_without_search.where(search_conditions)
24
- end
24
+ private
25
+
26
+ # Enhance the list entries with an optional search criteria
27
+ def list_entries
28
+ super.where(search_conditions)
29
+ end
25
30
 
26
- # Concat the word clauses with AND.
27
- def search_conditions
28
- if search_support? && params[:q].present?
29
- search_word_conditions.reduce do |query, condition|
30
- query.and(condition)
31
+ # Concat the word clauses with AND.
32
+ def search_conditions
33
+ if search_support? && params[:q].present?
34
+ search_word_conditions.reduce do |query, condition|
35
+ query.and(condition)
36
+ end
31
37
  end
32
38
  end
33
- end
34
39
 
35
- # Split the search query in single words and create a list of word clauses.
36
- def search_word_conditions
37
- params[:q].split(/\s+/).map { |w| search_word_condition(w) }
38
- end
40
+ # Split the search query in single words and create a list of word
41
+ # clauses.
42
+ def search_word_conditions
43
+ params[:q].split(/\s+/).map { |w| search_word_condition(w) }
44
+ end
39
45
 
40
- # Concat the column queries of the given word with OR.
41
- def search_word_condition(word)
42
- search_column_condition(word).reduce do |query, condition|
43
- query.or(condition)
46
+ # Concat the column queries of the given word with OR.
47
+ def search_word_condition(word)
48
+ search_column_condition(word).reduce do |query, condition|
49
+ query.or(condition)
50
+ end
51
+ end
52
+
53
+ # Create a list of Arel #matches queries for each column and the given
54
+ # word.
55
+ def search_column_condition(word)
56
+ self.class.search_tables_and_fields.map do |table_name, field|
57
+ table = Arel::Table.new(table_name)
58
+ table[field].matches(Arel::Nodes::Quoted.new("%#{word}%"))
59
+ end
44
60
  end
45
- end
46
61
 
47
- # Create a list of Arel #matches queries for each column and the given
48
- # word.
49
- def search_column_condition(word)
50
- self.class.search_tables_and_fields.map do |table_name, field|
51
- table = Arel::Table.new(table_name)
52
- table[field].matches("%#{word}%")
62
+ # Returns true if this controller has searchable columns.
63
+ def search_support?
64
+ search_columns.present?
53
65
  end
54
- end
55
66
 
56
- # Returns true if this controller has searchable columns.
57
- def search_support?
58
- search_columns.present?
59
67
  end
60
68
 
61
69
  # Class methods for Searchable.
@@ -71,6 +79,7 @@ module DryCrud
71
79
  end
72
80
  end
73
81
  end
82
+
74
83
  end
75
84
 
76
85
  end
@@ -1,10 +1,12 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module DryCrud
4
+
4
5
  # Sort functionality for the index table.
5
6
  # Define a default sort expression that is always appended to the
6
7
  # current sort params with the class attribute +default_sort+.
7
8
  module Sortable
9
+
8
10
  extend ActiveSupport::Concern
9
11
 
10
12
  included do
@@ -15,11 +17,12 @@ module DryCrud
15
17
 
16
18
  helper_method :sortable?
17
19
 
18
- alias_method_chain :list_entries, :sort
20
+ prepend Prepends
19
21
  end
20
22
 
21
23
  # Class methods for sorting.
22
24
  module ClassMethods
25
+
23
26
  # Define a map of (virtual) attributes to SQL order expressions.
24
27
  # May be used for sorting table columns that do not appear directly
25
28
  # in the database table. E.g., map city_id: 'cities.name' to
@@ -28,38 +31,45 @@ module DryCrud
28
31
  self.sort_mappings_with_indifferent_access =
29
32
  hash.with_indifferent_access
30
33
  end
34
+
31
35
  end
32
36
 
33
- private
37
+ # Prepended methods for sorting.
38
+ module Prepends
34
39
 
35
- # Enhance the list entries with an optional sort order.
36
- def list_entries_with_sort
37
- sortable = sortable?(params[:sort])
38
- if sortable || default_sort
39
- clause = [sortable ? sort_expression : nil, default_sort]
40
- list_entries_without_sort.reorder(clause.compact.join(', '))
41
- else
42
- list_entries_without_sort
40
+ private
41
+
42
+ # Enhance the list entries with an optional sort order.
43
+ def list_entries
44
+ sortable = sortable?(params[:sort])
45
+ if sortable || default_sort
46
+ clause = [sortable ? sort_expression : nil, default_sort]
47
+ super.reorder(clause.compact.join(', '))
48
+ else
49
+ super
50
+ end
43
51
  end
44
- end
45
52
 
46
- # Return the sort expression to be used in the list query.
47
- def sort_expression
48
- col = sort_mappings_with_indifferent_access[params[:sort]] ||
49
- "#{model_class.table_name}.#{params[:sort]}"
50
- "#{col} #{sort_dir}"
51
- end
53
+ # Return the sort expression to be used in the list query.
54
+ def sort_expression
55
+ col = sort_mappings_with_indifferent_access[params[:sort]] ||
56
+ "#{model_class.table_name}.#{params[:sort]}"
57
+ "#{col} #{sort_dir}"
58
+ end
52
59
 
53
- # The sort direction, either 'asc' or 'desc'.
54
- def sort_dir
55
- params[:sort_dir] == 'desc' ? 'DESC' : 'ASC'
56
- end
60
+ # The sort direction, either 'asc' or 'desc'.
61
+ def sort_dir
62
+ params[:sort_dir] == 'desc' ? 'DESC' : 'ASC'
63
+ end
64
+
65
+ # Returns true if the passed attribute is sortable.
66
+ def sortable?(attr)
67
+ attr.present? && (
68
+ model_class.column_names.include?(attr.to_s) ||
69
+ sort_mappings_with_indifferent_access.include?(attr))
70
+ end
57
71
 
58
- # Returns true if the passed attribute is sortable.
59
- def sortable?(attr)
60
- attr.present? && (
61
- model_class.column_names.include?(attr.to_s) ||
62
- sort_mappings_with_indifferent_access.include?(attr))
63
72
  end
73
+
64
74
  end
65
75
  end