rhino-rails 4.6.0 → 4.6.1

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: 3c800a5e70d40849b886fdd638cc4214fa4bd782965de5a94394a6fa0319cb38
4
- data.tar.gz: e967104d44d640b9645f579022f14831d36150e763497e25ecfbd2b391ec76b1
3
+ metadata.gz: ec046eac08bcbf895ec331091f9204e4abba36bf712dc2d283b2c91a02f36671
4
+ data.tar.gz: 9b72423cd739ed788cf2554b08aa7ba5f5d1dcbc4739689058bf6566b940f0f4
5
5
  SHA512:
6
- metadata.gz: 717d3ad2ef05fe9ead1918baa1d52d61e865f0b3cd95925173df147ae41ba66786a88971eeed21ef5729103d07312c4b3fdb0ffd5ed2a398e140e3abeebca670
7
- data.tar.gz: 0e20f9f6ee200c2643c691c4bac35a6acc6eb091103539b3271133c67f4093bae017bc5ce3b0955b2966ef1be1c688e30c4c17e28dd16566116e9beab5bee34e
6
+ metadata.gz: adc4639f14af9208841959882a089595573f910a67168551eca6c1cd6eb9d73e3f29523ad8ec49b0ce91e95692ca43b08c29a7d2b121605193c2e51d13b9a686
7
+ data.tar.gz: 7e6eb9a292a199dbf2f1c42b1e6970c3f99b7bc0df49d1b5318f5987ef1a5b5b070dc4cf01b613bbf035d40d001c8bfd8bf0c3dd1e27141f008da37b48689807
@@ -193,7 +193,7 @@ module Rhino
193
193
 
194
194
  # POST /api/{slug}/:id/restore
195
195
  def restore
196
- record = find_by_route_key(model_class.discarded)
196
+ record = find_by_route_key(organization_scoped(model_class.discarded))
197
197
  authorize record, :restore?, policy_class: policy_for(record)
198
198
 
199
199
  record.undiscard!
@@ -204,7 +204,7 @@ module Rhino
204
204
 
205
205
  # DELETE /api/{slug}/:id/force-delete
206
206
  def force_delete
207
- record = find_by_route_key(model_class.discarded)
207
+ record = find_by_route_key(organization_scoped(model_class.discarded))
208
208
  authorize record, :force_delete?, policy_class: policy_for(record)
209
209
 
210
210
  record.destroy!
@@ -487,14 +487,22 @@ module Rhino
487
487
  # ------------------------------------------------------------------
488
488
 
489
489
  def find_record
490
- scope = model_class.all
491
-
490
+ find_by_route_key(organization_scoped(model_class.all))
491
+ end
492
+
493
+ # Apply organization scoping to +relation+ for member-endpoint lookups
494
+ # (show/update/destroy/restore/force_delete). Delegates to the same lenient
495
+ # (non-strict) mechanisms index uses — organization-is-self,
496
+ # for_organization, organization_id column, auto-detected belongs_to path
497
+ # (incl. nested) — so records with an indirect tenant chain cannot be
498
+ # fetched cross-tenant by id/route key. Without an org context
499
+ # (single-tenant apps / non-tenant route groups) the relation is returned
500
+ # unchanged, and models with no scoping mechanism stay reachable as before.
501
+ def organization_scoped(relation)
492
502
  org = current_organization
493
- if org && model_class.column_names.include?("organization_id")
494
- scope = scope.where(organization_id: org.id)
495
- end
503
+ return relation unless org
496
504
 
497
- find_by_route_key(scope)
505
+ Rhino::ScopesToOrganization.scope_to_organization(relation, model_class, org)
498
506
  end
499
507
 
500
508
  # Column matched against the :id URL segment. Resolution chain:
@@ -30,9 +30,11 @@ module Rhino
30
30
  )
31
31
  end
32
32
 
33
- # Check for scopeForOrganization
33
+ # Check for scopeForOrganization. Merge into the incoming relation instead
34
+ # of replacing it so upstream conditions (e.g. `.discarded` for
35
+ # restore/force-delete lookups) are preserved alongside the org filter.
34
36
  if model_class.respond_to?(:for_organization)
35
- return model_class.for_organization(organization)
37
+ return relation.merge(model_class.for_organization(organization))
36
38
  end
37
39
 
38
40
  # Check for organization_id column
@@ -69,11 +71,16 @@ module Rhino
69
71
 
70
72
  def scope_through_relationship(relation, model_class, organization, relationship_path, strict: false)
71
73
  if relationship_path.include?(".")
72
- # Nested path: 'post.blog' -> joins(post: :blog).where(organizations: { id: org.id })
74
+ # Nested path: 'post.blog' -> joins(post: { blog: :organization })
75
+ # .where(organizations: { id: org.id })
76
+ # The inject already folds every path segment (outermost first) around
77
+ # the trailing :organization association, so the chain is passed to
78
+ # joins as-is — re-wrapping it in parts.first would double-nest the
79
+ # first segment and raise ActiveRecord::ConfigurationError.
73
80
  parts = relationship_path.split(".")
74
81
  join_chain = parts.reverse.inject(:organization) { |inner, outer| { outer.to_sym => inner } }
75
82
 
76
- relation.joins(join_chain.is_a?(Symbol) ? join_chain : parts.first.to_sym => join_chain)
83
+ relation.joins(join_chain)
77
84
  .where(organizations: { id: organization.id })
78
85
  else
79
86
  # Single relationship
data/lib/rhino/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rhino
4
- VERSION = "4.6.0"
4
+ VERSION = "4.6.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhino-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.0
4
+ version: 4.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Cipolla