crudable-rails 1.5.1 → 1.5.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bc075d091ac9fd062d7aa5c2ab7cceecaaa189c152d603a73006891650a661f
4
- data.tar.gz: 1cca79a75e27ec9fdf7d82b889030fc1c208caa63308993b2accf5226789a347
3
+ metadata.gz: fc3416b37cdcba0d62e5da5cc65373ffe498e077c209ab305303dbdd89942a42
4
+ data.tar.gz: e847455e16084ef8fa1610718f2aec087c45463a31770f88dd847c18c6358c61
5
5
  SHA512:
6
- metadata.gz: 9b8f108bf56e924eb6c47fafaeabacc2a2e2b94380cfd7cd885e9ded0bc4f36f83155d63449d1349b7a9c1a56d2a21ec6f9281d5668ffa5f3c4b3597f11628e9
7
- data.tar.gz: 00e9eb6393f9582fb722ea57794c5ba234eab1eecded762fd0d14760adae60098cfbc2c1d89d531b68e17fd2c2ad842b6acfff23c124578fa725cd8ace03660b
6
+ metadata.gz: 2d6abc3f5a289011d558a213bef542f380c31c5efedf8359dbceecb6f63d543f3ec53c0a294d68828d424ed9b234dc162f73f07de188bd533e045a31063f47f3
7
+ data.tar.gz: 49906b171b7f358709f59553cf0fd10677e0b4b90d379bd7c99a07bad1d4ab456e79573027ba50547abb2ac743df4b89fc1ed1b56a8c11c26babf2db847b1ad5
data/README.md CHANGED
@@ -231,7 +231,7 @@ The following private methods are available for use in your controllers:
231
231
 
232
232
  ### `after_create_redirect_path`
233
233
 
234
- This method should return the path to redirect to after a successful create. By default this will redirect to the namespaced index of the resource being created.
234
+ This method should return the path to redirect to after a successful create. By default this will redirect to the namespaced member (show) path of the resource being created, including any nest parents — the same shape as `after_update_redirect_path`.
235
235
 
236
236
  ### `after_create_notice`
237
237
 
data/Rakefile CHANGED
@@ -2,4 +2,8 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
 
5
+ Dir.glob('lib/tasks/**/*.rake', base: __dir__).sort.each { |task| load File.join(__dir__, task) }
6
+
5
7
  require 'bundler/gem_tasks'
8
+
9
+ Rake::Task['build'].enhance(['release:check'])
@@ -122,7 +122,9 @@ module Crudable
122
122
  resource = friendly_finders? ? resource_class.friendly : resource_class
123
123
  instance = find_instance(resource)
124
124
 
125
- return redirect_to (resource_namespace + [instance]), status: :moved_permanently if should_redirect?(instance)
125
+ # url_for keeps the current action/path parents and only swaps the finder param
126
+ # (e.g. numeric id → slug on edit stays on edit, not show).
127
+ return redirect_to url_for(finder_param => instance.to_param), status: :moved_permanently if should_redirect?(instance)
126
128
 
127
129
  instance_variable_set("@#{resource_var_name}", instance)
128
130
  rescue ActiveRecord::RecordNotFound
@@ -155,7 +157,27 @@ module Crudable
155
157
  end
156
158
 
157
159
  def should_redirect?(instance)
158
- friendly_finders? && request.path != polymorphic_path(resource_namespace + [instance])
160
+ friendly_finders? && params[finder_param].to_s != instance.to_param.to_s
161
+ end
162
+
163
+ # Polymorphic args for a member path, including namespace and nest parents.
164
+ # e.g. [:admin, account, product] → admin_account_product_path
165
+ def resource_member_path_args(instance = nil)
166
+ instance ||= instance_variable_get("@#{resource_var_name}")
167
+ resource_namespace + resource_path_parents + [instance]
168
+ end
169
+
170
+ # Loaded path parents in route order (supports multi-level nesting when Nestable
171
+ # has set each parent ivar, including intermediate ones).
172
+ def resource_path_parents
173
+ return [] unless respond_to?(:parent_present?, true) && parent_present?
174
+ return [] unless respond_to?(:parent_id_param_keys, true)
175
+
176
+ parent_id_param_keys.map(&:to_s).filter_map do |key|
177
+ next unless key.end_with?('_id')
178
+
179
+ instance_variable_get("@#{key.delete_suffix('_id')}")
180
+ end
159
181
  end
160
182
 
161
183
  def singleton?
@@ -222,15 +244,7 @@ module Crudable
222
244
  end
223
245
 
224
246
  def after_create_redirect_path
225
- if respond_to?(:parent_present?) && parent_present? && instance_variable_get("@#{parent_var_name}")
226
- parent = instance_variable_get("@#{parent_var_name}")
227
- resource_namespace + [parent, plural_resource_var_name.to_sym]
228
- else
229
- resource_namespace + [plural_resource_var_name.to_sym]
230
- end
231
- rescue NoMethodError
232
- # Fallback if parent_present? or parent_var_name methods aren't available
233
- resource_namespace + [plural_resource_var_name.to_sym]
247
+ resource_member_path_args
234
248
  end
235
249
 
236
250
  def after_create_notice
@@ -238,7 +252,7 @@ module Crudable
238
252
  end
239
253
 
240
254
  def after_update_redirect_path
241
- resource_namespace + [instance_variable_get("@#{resource_var_name}")]
255
+ resource_member_path_args
242
256
  end
243
257
 
244
258
  def after_update_notice
@@ -13,10 +13,7 @@ module Crudable
13
13
  def find_parent
14
14
  return unless parent_present?
15
15
 
16
- parent_scope = parent_class
17
- parent_scope = parent_class.friendly if parent_friendly_finders?
18
- instance_variable_set("@#{parent_var_name}", parent_scope.find(params[parent_id_param]))
19
- self.class.send(:decorates_assigned, parent_var_name.to_sym) if defined?(Draper)
16
+ load_path_parents
20
17
  rescue ActiveRecord::RecordNotFound => e
21
18
  # Only catch and render 404 if we're in a request context
22
19
  # Check if we have a request object (indicates we're in a request context)
@@ -26,6 +23,45 @@ module Crudable
26
23
  nil # Explicitly stop execution to prevent further action execution
27
24
  end
28
25
 
26
+ # Loads every `*_id` path parent (shallow → deep) so multi-level nested routes
27
+ # can build polymorphic member paths that include the full ancestor chain.
28
+ # Scoping still uses the deepest parent via parent_id_param / parent_var_name.
29
+ def load_path_parents
30
+ parent_id_param_keys.map(&:to_s).grep(/\A(.+)_id\z/).each do |key|
31
+ load_path_parent(key)
32
+ end
33
+ end
34
+
35
+ def load_path_parent(key)
36
+ var_name = key.sub(/_id\z/, '')
37
+ return if instance_variable_get("@#{var_name}").present?
38
+
39
+ klass = parent_class_for(key)
40
+ scope = parent_find_scope_for(klass, key)
41
+ instance_variable_set("@#{var_name}", scope.find(params[key]))
42
+ self.class.send(:decorates_assigned, var_name.to_sym) if defined?(Draper)
43
+ end
44
+
45
+ # Resolve the model class for a path parent param.
46
+ # Deepest parent uses #parent_class so controllers can override for namespaced models
47
+ # (e.g. Admin::Client). Override this for non-default intermediate parents.
48
+ def parent_class_for(key)
49
+ if key.to_s == parent_id_param.to_s
50
+ parent_class
51
+ else
52
+ key.to_s.sub(/_id\z/, '').classify.constantize
53
+ end
54
+ end
55
+
56
+ def parent_find_scope_for(klass, key)
57
+ use_friendly = if key.to_s == parent_id_param.to_s
58
+ parent_friendly_finders?
59
+ else
60
+ defined?(FriendlyId) && klass.respond_to?(:friendly) && friendly_finders?
61
+ end
62
+ use_friendly ? klass.friendly : klass
63
+ end
64
+
29
65
  def parent_id_param
30
66
  return nil unless use_parent_as_scope?
31
67
 
@@ -3,6 +3,6 @@
3
3
  # Crudable Version
4
4
  module Crudable
5
5
  module Rails
6
- VERSION = '1.5.1'
6
+ VERSION = '1.5.2'
7
7
  end
8
8
  end
@@ -124,15 +124,13 @@ class <%= controller_class_name %>Controller < ApplicationController
124
124
  # end
125
125
  #
126
126
  # # Customize success redirects/flash messages.
127
+ # # Defaults redirect create/update to the member path (including nest parents).
127
128
  # def after_create_redirect_path
128
- # if respond_to?(:parent_present?) && parent_present? && instance_variable_get("@#{parent_var_name}")
129
- # parent = instance_variable_get("@#{parent_var_name}")
130
- # resource_namespace + [parent, :<%= plural_table_name %>]
129
+ # if parent_present?
130
+ # resource_namespace + [instance_variable_get("@#{parent_var_name}"), @<%= singular_table_name %>]
131
131
  # else
132
- # resource_namespace + [:<%= plural_table_name %>]
132
+ # resource_namespace + [@<%= singular_table_name %>]
133
133
  # end
134
- # rescue NoMethodError
135
- # resource_namespace + [:<%= plural_table_name %>]
136
134
  # end
137
135
  #
138
136
  # def after_create_notice
@@ -140,7 +138,11 @@ class <%= controller_class_name %>Controller < ApplicationController
140
138
  # end
141
139
  #
142
140
  # def after_update_redirect_path
143
- # resource_namespace + [@<%= singular_table_name %>]
141
+ # if parent_present?
142
+ # resource_namespace + [instance_variable_get("@#{parent_var_name}"), @<%= singular_table_name %>]
143
+ # else
144
+ # resource_namespace + [@<%= singular_table_name %>]
145
+ # end
144
146
  # end
145
147
  #
146
148
  # def after_update_notice
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :release do
4
+ desc 'Fail if any lib/ file is not world-readable (run before gem build)'
5
+ task :check do
6
+ root = File.expand_path('../..', __dir__)
7
+
8
+ non_readable = Dir.chdir(root) do
9
+ `find lib -type f ! -perm -004`.strip.split("\n").reject(&:empty?)
10
+ end
11
+
12
+ if non_readable.any?
13
+ warn 'The following files under lib/ are not world-readable (need at least o+r):'
14
+ non_readable.each { |path| warn " #{path}" }
15
+ abort 'release:check failed'
16
+ end
17
+
18
+ puts 'release:check passed (all lib/ files are world-readable)'
19
+ end
20
+
21
+ desc 'Verify a built .gem has world-readable lib/ files (default: newest pkg/crudable-rails-*.gem)'
22
+ task :verify_gem, [:gem_path] do |_task, args|
23
+ root = File.expand_path('../..', __dir__)
24
+ gem_path = args[:gem_path]
25
+ if gem_path.nil? || gem_path.empty?
26
+ candidates = Dir.glob(File.join(root, 'pkg', 'crudable-rails-*.gem'))
27
+ abort 'No gem found under pkg/. Run gem build first or pass gem_path.' if candidates.empty?
28
+
29
+ gem_path = candidates.max_by { |path| File.mtime(path) }
30
+ else
31
+ gem_path = File.expand_path(gem_path, root)
32
+ end
33
+
34
+ abort "Gem not found: #{gem_path}" unless File.file?(gem_path)
35
+
36
+ listing = `tar -xOf "#{gem_path}" data.tar.gz | tar -tvzf -`
37
+ abort 'Could not read gem contents' if listing.empty?
38
+
39
+ bad_entries = listing.lines.map(&:chomp).select do |line|
40
+ path = line.split.last
41
+ next false unless path.start_with?('lib/')
42
+
43
+ mode = line.split.first
44
+ next true unless mode&.start_with?('-')
45
+
46
+ mode[7] != 'r' # other-read in ls -l style (-rwxrwxrwx)
47
+ end
48
+
49
+ if bad_entries.any?
50
+ warn 'The following paths in the gem are not world-readable:'
51
+ bad_entries.each { |entry| warn " #{entry}" }
52
+ abort 'release:verify_gem failed'
53
+ end
54
+
55
+ controller_line = `tar -xOf "#{gem_path}" data.tar.gz | tar -tvzf - | grep 'lib/crudable/rails/controller.rb'`.strip
56
+ puts 'release:verify_gem passed'
57
+ puts controller_line if controller_line && !controller_line.empty?
58
+ end
59
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crudable-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomislav Simnett
@@ -121,6 +121,7 @@ files:
121
121
  - lib/generators/crudable/templates/turbo_forms/edit.turbo_stream.erb.tt
122
122
  - lib/generators/crudable/templates/turbo_forms/new.turbo_stream.erb.tt
123
123
  - lib/tasks/crudable_tasks.rake
124
+ - lib/tasks/release.rake
124
125
  homepage: https://gitlab.com/initforthe/crudable-rails
125
126
  licenses:
126
127
  - MIT