├── .github
├── FUNDING.yml
├── dependabot.yml
├── release.yml
└── workflows
│ ├── ci.yaml
│ ├── github-actions-lint.yml
│ ├── rubocop.yml
│ └── yaml-lint.yml
├── .gitignore
├── .rubocop.yml
├── .yamllint.yml
├── CHANGELOG.md
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├── README.md
├── Rakefile
├── app
└── controllers
│ └── inherited_resources
│ └── base.rb
├── bin
├── bundle
├── rake
└── rubocop
├── codecov.yml
├── gemfiles
├── rails_70
│ ├── Gemfile
│ └── Gemfile.lock
├── rails_71
│ ├── Gemfile
│ └── Gemfile.lock
└── rails_72
│ ├── Gemfile
│ └── Gemfile.lock
├── inherited_resources.gemspec
├── lib
├── generators
│ └── rails
│ │ ├── USAGE
│ │ ├── inherited_resources_controller_generator.rb
│ │ └── templates
│ │ └── controller.rb.tt
├── inherited_resources.rb
└── inherited_resources
│ ├── actions.rb
│ ├── base_helpers.rb
│ ├── belongs_to_helpers.rb
│ ├── blank_slate.rb
│ ├── class_methods.rb
│ ├── dsl.rb
│ ├── engine.rb
│ ├── polymorphic_helpers.rb
│ ├── responder.rb
│ ├── shallow_helpers.rb
│ ├── singleton_helpers.rb
│ ├── url_helpers.rb
│ └── version.rb
└── test
├── aliases_test.rb
├── association_chain_test.rb
├── autoload
└── engine.rb
├── base_test.rb
├── belongs_to_test.rb
├── belongs_to_with_shallow_test.rb
├── changelog_test.rb
├── class_methods_test.rb
├── customized_base_test.rb
├── customized_belongs_to_test.rb
├── customized_redirect_to_test.rb
├── defaults_test.rb
├── locales
└── en.yml
├── multiple_nested_optional_belongs_to_test.rb
├── nested_belongs_to_test.rb
├── nested_belongs_to_with_shallow_test.rb
├── nested_model_with_shallow_test.rb
├── nested_singleton_test.rb
├── optional_belongs_to_test.rb
├── parent_controller_test.rb
├── polymorphic_test.rb
├── redirect_to_test.rb
├── singleton_test.rb
├── strong_parameters_test.rb
├── tasks
├── gemfile_test.rb
└── gemspec_test.rb
├── test_helper.rb
├── url_helpers_test.rb
└── views
├── address
├── edit.html.erb
├── new.html.erb
└── show.html.erb
├── cars
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── cities
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── comments
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── educations
└── new.html.erb
├── employees
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── geolocation
└── show.html.erb
├── groups
└── edit.html.erb
├── managers
├── edit.html.erb
├── new.html.erb
└── show.html.erb
├── painters
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── pets
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── photos
└── index.html.erb
├── plates
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── products
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── professors
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── projects
├── edit.html.erb
├── index.html.erb
├── index.json.erb
├── new.html.erb
├── respond_to_skip_default_template.html.erb
├── respond_with_resource.html.erb
└── show.html.erb
├── students
├── edit.html.erb
└── new.html.erb
├── tags
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── trees
├── edit.html.erb
├── index.html.erb
├── new.html.erb
└── show.html.erb
├── university
└── lecturers
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── new.html.erb
│ └── show.html.erb
├── users
├── create.js.erb
├── destroy.js.erb
├── edit.html.erb
├── index.html.erb
├── new.html.erb
├── show.html.erb
└── update.js.erb
├── venue
└── show.html.erb
└── widgets
└── new.html.erb
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | tidelift: rubygems/inherited_resources
4 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: github-actions
4 | directory: /
5 | schedule:
6 | interval: daily
7 | groups:
8 | github_actions:
9 | patterns:
10 | - "*"
11 | - package-ecosystem: bundler
12 | directory: /
13 | schedule:
14 | interval: monthly
15 | versioning-strategy: lockfile-only
16 | groups:
17 | rails_default:
18 | patterns:
19 | - "*"
20 | - package-ecosystem: bundler
21 | directory: /gemfiles/rails_61
22 | schedule:
23 | interval: monthly
24 | versioning-strategy: lockfile-only
25 | groups:
26 | rails_61:
27 | patterns:
28 | - "*"
29 | - package-ecosystem: bundler
30 | directory: /gemfiles/rails_70
31 | schedule:
32 | interval: monthly
33 | versioning-strategy: lockfile-only
34 | groups:
35 | rails_70:
36 | patterns:
37 | - "*"
38 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | categories:
3 | - title: Breaking Changes 🚨
4 | labels:
5 | - type breaking change
6 | - title: Enhancements ✨
7 | labels:
8 | - type enhancement
9 | - title: Bug Fixes 🐛
10 | labels:
11 | - type bug fix
12 | - title: Security Fixes 🔒
13 | labels:
14 | - type security fix
15 | - title: Other Changes 🛠
16 | labels:
17 | - "*"
18 | exclude:
19 | authors:
20 | - dependabot
21 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - master
8 |
9 | jobs:
10 | test:
11 | name: test (ruby-${{ matrix.ruby }}, ${{ matrix.rails }})
12 | runs-on: ubuntu-latest
13 | timeout-minutes: 15
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | ruby:
18 | - "3.1"
19 | - "3.2"
20 | - "3.3"
21 | - "3.4"
22 | rails:
23 | - rails_70
24 | - rails_71
25 | - rails_72
26 | - rails_80
27 | exclude:
28 | - ruby: "3.1"
29 | rails: rails_80
30 | - ruby: "3.4"
31 | rails: rails_70
32 | steps:
33 | - uses: actions/checkout@v4
34 | - name: Configure bundler (default)
35 | run: |
36 | echo "BUNDLE_GEMFILE=Gemfile" >> "$GITHUB_ENV"
37 | if: matrix.rails == 'rails_80'
38 | - name: Configure bundler (alternative)
39 | run: |
40 | echo "BUNDLE_GEMFILE=gemfiles/${{ matrix.rails }}/Gemfile" >> "$GITHUB_ENV"
41 | if: matrix.rails != 'rails_80'
42 | - uses: ruby/setup-ruby@v1
43 | with:
44 | ruby-version: ${{ matrix.ruby }}
45 | bundler-cache: true
46 | - name: Run tests
47 | env:
48 | COVERAGE: true
49 | run: |
50 | bundle exec rake test TESTOPTS="--verbose"
51 | mv coverage/coverage.xml coverage/coverage-ruby-${{ matrix.ruby }}-${{ matrix.rails }}.xml
52 | - uses: actions/upload-artifact@v4
53 | with:
54 | name: coverage-ruby-${{ matrix.ruby }}-${{ matrix.rails }}
55 | path: coverage
56 | if-no-files-found: error
57 |
58 | upload_coverage:
59 | name: Upload Coverage
60 | runs-on: ubuntu-latest
61 | needs:
62 | - test
63 | steps:
64 | - uses: actions/checkout@v4
65 | - uses: actions/download-artifact@v4
66 | with:
67 | pattern: coverage-ruby-*
68 | path: coverage
69 | merge-multiple: true
70 | - uses: codecov/codecov-action@v5
71 | with:
72 | token: ${{ secrets.CODECOV_TOKEN }}
73 | directory: coverage
74 | fail_ci_if_error: true
75 |
--------------------------------------------------------------------------------
/.github/workflows/github-actions-lint.yml:
--------------------------------------------------------------------------------
1 | name: GitHub Actions Lint
2 |
3 | on:
4 | pull_request:
5 |
6 | jobs:
7 | github_actions_lint:
8 | name: Run actionlint
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | - uses: tj-actions/changed-files@v46
13 | id: changed-files
14 | with:
15 | files: |
16 | .github/workflows/*.yaml
17 | .github/workflows/*.yml
18 | - uses: reviewdog/action-actionlint@v1
19 | if: steps.changed-files.outputs.any_changed == 'true'
20 | with:
21 | fail_level: any
22 | filter_mode: nofilter # added (default), diff_context, file, nofilter
23 | github_token: ${{ secrets.GITHUB_TOKEN }}
24 | reporter: github-pr-check
25 |
--------------------------------------------------------------------------------
/.github/workflows/rubocop.yml:
--------------------------------------------------------------------------------
1 | name: Rubocop
2 |
3 | on:
4 | pull_request:
5 |
6 | env:
7 | RUBY_VERSION: ${{ vars.RUBOCOP_RUBY_VERSION || '3.4' }}
8 |
9 | jobs:
10 | rubocop:
11 | name: Run rubocop
12 | runs-on: ubuntu-latest
13 | env:
14 | BUNDLE_ONLY: ${{ vars.RUBOCOP_BUNDLE_ONLY || 'rubocop' }}
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: tj-actions/changed-files@v46
18 | id: changed-files
19 | with:
20 | files: |
21 | .github/workflows/rubocop.yml
22 | .rubocop.yml
23 | **.rb
24 | bin/*
25 | gemfiles/**/Gemfile
26 | Gemfile*
27 | Rakefile
28 | *.gemspec
29 | - uses: ruby/setup-ruby@v1
30 | if: steps.changed-files.outputs.any_changed == 'true'
31 | with:
32 | ruby-version: ${{ env.RUBY_VERSION }}
33 | bundler-cache: true
34 | - uses: reviewdog/action-rubocop@v2
35 | if: steps.changed-files.outputs.any_changed == 'true'
36 | with:
37 | fail_level: any
38 | filter_mode: nofilter # added (default), diff_context, file, nofilter
39 | github_token: ${{ secrets.GITHUB_TOKEN }}
40 | skip_install: true
41 | use_bundler: true
42 |
--------------------------------------------------------------------------------
/.github/workflows/yaml-lint.yml:
--------------------------------------------------------------------------------
1 | name: YAML Lint
2 |
3 | on:
4 | pull_request:
5 |
6 | jobs:
7 | yaml_lint:
8 | name: Run yamllint
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | - uses: tj-actions/changed-files@v46
13 | id: changed-files
14 | with:
15 | files: |
16 | **.yaml
17 | **.yml
18 | - uses: reviewdog/action-yamllint@v1
19 | if: steps.changed-files.outputs.any_changed == 'true'
20 | with:
21 | fail_level: any
22 | filter_mode: nofilter # added (default), diff_context, file, nofilter
23 | github_token: ${{ secrets.GITHUB_TOKEN }}
24 | reporter: github-pr-check
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle
2 | pkg
3 | coverage
4 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | plugins:
4 | - rubocop-minitest
5 | - rubocop-packaging
6 | - rubocop-performance
7 |
8 | AllCops:
9 | DisabledByDefault: true
10 |
11 | DisplayCopNames: true
12 | DisplayStyleGuide: true
13 |
14 | TargetRubyVersion: 3.1
15 |
16 | Metrics:
17 | Enabled: false
18 |
19 | Layout/CommentIndentation:
20 | Enabled: true
21 |
22 | Layout/EndAlignment:
23 | EnforcedStyleAlignWith: variable
24 | Enabled: true
25 |
26 | Layout/EmptyLines:
27 | Enabled: true
28 |
29 | Layout/EmptyLinesAroundAccessModifier:
30 | Enabled: true
31 |
32 | Layout/EmptyLinesAroundClassBody:
33 | Enabled: true
34 |
35 | Layout/IndentationConsistency:
36 | Enabled: true
37 | EnforcedStyle: indented_internal_methods
38 |
39 | Layout/IndentationWidth:
40 | Enabled: true
41 |
42 | Layout/IndentationStyle:
43 | Enabled: true
44 |
45 | Layout/TrailingWhitespace:
46 | Enabled: true
47 |
48 | Layout/TrailingEmptyLines:
49 | Enabled: true
50 |
51 | Lint/AmbiguousOperator:
52 | Enabled: true
53 |
54 | Lint/AmbiguousRegexpLiteral:
55 | Enabled: true
56 |
57 | Lint/UselessAssignment:
58 | Enabled: true
59 |
60 | Minitest:
61 | Enabled: true
62 |
63 | Minitest/AssertEmpty:
64 | Enabled: true
65 |
66 | Minitest/AssertEmptyLiteral:
67 | Enabled: true
68 |
69 | Minitest/AssertEqual:
70 | Enabled: true
71 |
72 | Minitest/AssertInDelta:
73 | Enabled: true
74 |
75 | Minitest/AssertIncludes:
76 | Enabled: true
77 |
78 | Minitest/AssertInstanceOf:
79 | Enabled: true
80 |
81 | Minitest/AssertKindOf:
82 | Enabled: true
83 |
84 | Minitest/AssertMatch:
85 | Enabled: true
86 |
87 | Minitest/AssertNil:
88 | Enabled: true
89 |
90 | Minitest/AssertOperator:
91 | Enabled: true
92 |
93 | Minitest/AssertOutput:
94 | Enabled: true
95 |
96 | Minitest/AssertPathExists:
97 | Enabled: true
98 |
99 | Minitest/AssertPredicate:
100 | Enabled: true
101 |
102 | Minitest/AssertRaisesCompoundBody:
103 | Enabled: true
104 |
105 | Minitest/AssertRaisesWithRegexpArgument:
106 | Enabled: true
107 |
108 | Minitest/AssertRespondTo:
109 | Enabled: true
110 |
111 | Minitest/AssertSame:
112 | Enabled: true
113 |
114 | Minitest/AssertSilent:
115 | Enabled: true
116 |
117 | Minitest/AssertTruthy:
118 | Enabled: true
119 |
120 | Minitest/AssertWithExpectedArgument:
121 | Enabled: true
122 |
123 | Minitest/AssertionInLifecycleHook:
124 | Enabled: true
125 |
126 | Minitest/DuplicateTestRun:
127 | Enabled: true
128 |
129 | Minitest/EmptyLineBeforeAssertionMethods:
130 | Enabled: true
131 |
132 | Minitest/Focus:
133 | Enabled: true
134 |
135 | Minitest/GlobalExpectations:
136 | Enabled: true
137 |
138 | Minitest/LifecycleHooksOrder:
139 | Enabled: true
140 |
141 | Minitest/LiteralAsActualArgument:
142 | Enabled: true
143 |
144 | Minitest/MultipleAssertions:
145 | Enabled: false
146 |
147 | Minitest/NoAssertions:
148 | Enabled: true
149 |
150 | Minitest/NoTestCases:
151 | Enabled: true
152 |
153 | Minitest/NonExecutableTestMethod:
154 | Enabled: true
155 |
156 | Minitest/NonPublicTestMethod:
157 | Enabled: true
158 |
159 | Minitest/RedundantMessageArgument:
160 | Enabled: true
161 |
162 | Minitest/RefuteEmpty:
163 | Enabled: true
164 |
165 | Minitest/RefuteEqual:
166 | Enabled: true
167 |
168 | Minitest/RefuteFalse:
169 | Enabled: true
170 |
171 | Minitest/RefuteInDelta:
172 | Enabled: true
173 |
174 | Minitest/RefuteIncludes:
175 | Enabled: true
176 |
177 | Minitest/RefuteInstanceOf:
178 | Enabled: true
179 |
180 | Minitest/RefuteKindOf:
181 | Enabled: true
182 |
183 | Minitest/RefuteMatch:
184 | Enabled: true
185 |
186 | Minitest/RefuteNil:
187 | Enabled: true
188 |
189 | Minitest/RefuteOperator:
190 | Enabled: true
191 |
192 | Minitest/RefutePathExists:
193 | Enabled: true
194 |
195 | Minitest/RefutePredicate:
196 | Enabled: true
197 |
198 | Minitest/RefuteRespondTo:
199 | Enabled: true
200 |
201 | Minitest/RefuteSame:
202 | Enabled: true
203 |
204 | Minitest/ReturnInTestMethod:
205 | Enabled: true
206 |
207 | Minitest/SkipEnsure:
208 | Enabled: true
209 |
210 | Minitest/SkipWithoutReason:
211 | Enabled: true
212 |
213 | Minitest/TestFileName:
214 | Enabled: true
215 |
216 | Minitest/TestMethodName:
217 | Enabled: true
218 |
219 | Minitest/UnreachableAssertion:
220 | Enabled: true
221 |
222 | Minitest/UnspecifiedException:
223 | Enabled: true
224 |
225 | Minitest/UselessAssertion:
226 | Enabled: true
227 |
228 | Packaging/BundlerSetupInTests:
229 | Enabled: true
230 |
231 | Packaging/GemspecGit:
232 | Enabled: true
233 |
234 | Packaging/RequireHardcodingLib:
235 | Enabled: true
236 |
237 | Packaging/RequireRelativeHardcodingLib:
238 | Enabled: true
239 |
240 | Performance:
241 | Enabled: true
242 |
243 | Performance/AncestorsInclude:
244 | Enabled: false
245 |
246 | Performance/ArraySemiInfiniteRangeSlice:
247 | Enabled: false
248 |
249 | Performance/BigDecimalWithNumericArgument:
250 | Enabled: true
251 |
252 | Performance/BindCall:
253 | Enabled: true
254 |
255 | Performance/BlockGivenWithExplicitBlock:
256 | Enabled: true
257 |
258 | Performance/Caller:
259 | Enabled: true
260 |
261 | Performance/CaseWhenSplat:
262 | Enabled: true
263 |
264 | Performance/Casecmp:
265 | Enabled: false
266 |
267 | Performance/ChainArrayAllocation:
268 | Enabled: false
269 |
270 | Performance/CollectionLiteralInLoop:
271 | Enabled: true
272 | Exclude:
273 | - spec/**/*
274 |
275 | Performance/CompareWithBlock:
276 | Enabled: true
277 |
278 | Performance/ConcurrentMonotonicTime:
279 | Enabled: true
280 |
281 | Performance/ConstantRegexp:
282 | Enabled: true
283 |
284 | Performance/Count:
285 | Enabled: true
286 |
287 | Performance/DeletePrefix:
288 | Enabled: true
289 |
290 | Performance/DeleteSuffix:
291 | Enabled: true
292 |
293 | Performance/Detect:
294 | Enabled: true
295 |
296 | Performance/DoubleStartEndWith:
297 | Enabled: true
298 | IncludeActiveSupportAliases: true
299 |
300 | Performance/EndWith:
301 | Enabled: true
302 |
303 | Performance/FixedSize:
304 | Enabled: true
305 |
306 | Performance/FlatMap:
307 | Enabled: true
308 | EnabledForFlattenWithoutParams: false
309 |
310 | Performance/InefficientHashSearch:
311 | Enabled: true
312 |
313 | Performance/IoReadlines:
314 | Enabled: true
315 |
316 | Performance/MapCompact:
317 | Enabled: false
318 |
319 | Performance/MapMethodChain:
320 | Enabled: false
321 |
322 | Performance/MethodObjectAsBlock:
323 | Enabled: true
324 |
325 | Performance/OpenStruct:
326 | Enabled: true
327 |
328 | Performance/RangeInclude:
329 | Enabled: true
330 |
331 | Performance/RedundantBlockCall:
332 | Enabled: false
333 |
334 | Performance/RedundantEqualityComparisonBlock:
335 | Enabled: false
336 |
337 | Performance/RedundantMatch:
338 | Enabled: true
339 |
340 | Performance/RedundantMerge:
341 | Enabled: true
342 | MaxKeyValuePairs: 2
343 |
344 | Performance/RedundantSortBlock:
345 | Enabled: true
346 |
347 | Performance/RedundantSplitRegexpArgument:
348 | Enabled: true
349 |
350 | Performance/RedundantStringChars:
351 | Enabled: true
352 |
353 | Performance/RegexpMatch:
354 | Enabled: true
355 |
356 | Performance/ReverseEach:
357 | Enabled: true
358 |
359 | Performance/ReverseFirst:
360 | Enabled: true
361 |
362 | Performance/SelectMap:
363 | Enabled: false
364 |
365 | Performance/Size:
366 | Enabled: true
367 |
368 | Performance/SortReverse:
369 | Enabled: true
370 |
371 | Performance/Squeeze:
372 | Enabled: true
373 |
374 | Performance/StartWith:
375 | Enabled: true
376 |
377 | Performance/StringBytesize:
378 | Enabled: true
379 |
380 | Performance/StringIdentifierArgument:
381 | Enabled: true
382 |
383 | Performance/StringInclude:
384 | Enabled: true
385 |
386 | Performance/StringReplacement:
387 | Enabled: true
388 |
389 | Performance/Sum:
390 | Enabled: false
391 |
392 | Performance/TimesMap:
393 | Enabled: true
394 |
395 | Performance/UnfreezeString:
396 | Enabled: true
397 |
398 | Performance/UriDefaultParser:
399 | Enabled: true
400 |
401 | Performance/ZipWithoutBlock:
402 | Enabled: true
403 |
404 | Style/Encoding:
405 | Enabled: true
406 |
407 | Style/FrozenStringLiteralComment:
408 | Enabled: true
409 | Exclude:
410 | - bin/console
411 |
412 | Style/HashSyntax:
413 | Enabled: true
414 |
--------------------------------------------------------------------------------
/.yamllint.yml:
--------------------------------------------------------------------------------
1 | # https://yamllint.readthedocs.io/en/stable/configuration.html
2 | extends: default
3 | ignore: |
4 | tmp/
5 | vendor/
6 | rules: # https://yamllint.readthedocs.io/en/stable/rules.html
7 | comments:
8 | min-spaces-from-content: 1
9 | document-start: disable
10 | line-length: disable
11 | truthy:
12 | allowed-values:
13 | - "true"
14 | - "false"
15 | - "on"
16 | - "off"
17 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## Version 2.1.0
4 |
5 | * Support for setting the parent controller class [#903][]
6 | * Remove support for Ruby `< 3.1`
7 | * Remove support for Rails `< 7.0`
8 | * Test against Rails 8.0
9 |
10 | ## Version 2.0.1
11 |
12 | * Prefer `require_relative` for internal requires [#939][]
13 |
14 | ## Version 2.0.0
15 |
16 | * Test against Rails 7.2 [#921][]
17 | * Add frozen string literal to `InheritedResources` module [#933][]
18 | * Change return codes to new Responders defaults [#918][]
19 |
20 | ## Version 1.14.0
21 |
22 | * Remove upper bound dependency limits from gemspec
23 | * Allow using Rails 7.1 [#873][]
24 | * Remove support for Ruby `< 2.6`
25 |
26 | ## Version 1.13.1
27 |
28 | * Allow using Rails 7.0
29 |
30 | ## Version 1.13.0
31 |
32 | * Remove support for Ruby `< 2.5`
33 | * Coerce `:route_prefix` config option to a Symbol, ensuring compatibility with Rails versions that have resolved CVE-2021-22885
34 |
35 | ## Version 1.12.0
36 |
37 | * Remove support for Rails 5.0 and Rails 5.1
38 | * Allow using Rails 6.1
39 |
40 | ## Version 1.11.0
41 |
42 | * Add support for responders `>= 3.0`
43 | * Remove support for Ruby `< 2.4`
44 |
45 | ## Version 1.10.0
46 |
47 | _No changes_
48 |
49 | ## Version 1.10.0.rc1
50 |
51 | * Preliminary support for Rails 6.0
52 | * Remove support for Rails 4.2
53 |
54 | ## Version 1.9.0
55 |
56 | * Support Rails 5.2.1
57 | * Remove support for Ruby `< 2.3`
58 |
59 | ## Version 1.8.0
60 |
61 | * Support Rails 5.2
62 | * Supports Ruby 2.4
63 | * Remove support for Ruby `< 2.2`, and Rails `< 4.2`
64 | * Fixed broken class name in belongs_to
65 | * Remove use of HttpCacheResponder
66 | * Correct request_name in isolated engines
67 | * Fix nested controllers and singleton option
68 |
69 | ## Version 1.7.2
70 |
71 | * Support Rails 5.1
72 |
73 | ## Version 1.7.1
74 |
75 | * Fix regression with `get_resource_ivar` that was returning `false` instead of `nil` when the value was not set
76 | * Do not load `ActionController::Base` on boot time
77 |
78 | ## Version 1.7.0
79 |
80 | * Support Rails 5
81 | * Remove support for Ruby `< 2.1`
82 | * Fix URL helpers on mountable engines
83 | * Allow support to has_scope `< 0.6` and `> 1.0`. Users are now able to choose which version they want to use in their applications
84 |
85 | ## Version 1.6.0
86 |
87 | * Support Rails 4.2
88 |
89 | ## Version 1.5.1
90 |
91 | * Lock the Rails version until only 4.2
92 | * Fix parent class lookup
93 | * Fix resource_class default value definition
94 |
95 | ## Version 1.5.0
96 |
97 | * Supports nested modules (namespaced models and controllers)
98 | * Supports Rails 4 Strong Parameters notation
99 |
100 | ## Version 1.4.1
101 |
102 | * Supports Rails 4
103 | * Improved compatibility with strong params
104 |
105 | ## Version 1.4.0
106 |
107 | * Supports Ruby 2.0.0
108 | * Added support for the strong_parameters gem. See the README for more
109 | * Added the ability to pass without_protection when creating/updating
110 | * Fixed multi-level nested singletons
111 | * Correct paths now generated for uncountable shallow resources
112 |
113 | ## Version 1.3.1
114 |
115 | * Fix polymorphic_belongs_to to get the parent
116 | * Added support for Rails 3.2
117 | * Added support to responders >= 0.6.0
118 |
119 | ## Version 1.3.0
120 |
121 | * Added support for multiple polymorphic optional nesting
122 | * Fix nested namespace in mountable apps
123 | * Added support for rails 3.1 new mass assignment conventions
124 | * Turn InheritedResources::Base into a reloadable constant to fix reloading issues
125 |
126 | ## Version 1.2.2
127 |
128 | * Fix a bug in params parsing
129 | * Call .scoped only if it is available
130 |
131 | ## Version 1.2.1
132 |
133 | * Fix a bug with namespaces
134 | * Use Post.scoped instead of Post.all in collection
135 |
136 | ## Version 1.2
137 |
138 | * Improved lookup for namespaces (by github.com/Sirupsen)
139 | * Support to custom actions (by github.com/lda)
140 | * Rails 3.1 compatibility (by github.com/etehtsea)
141 |
142 | ## Version 1.1
143 |
144 | * Rails 3 compatible
145 |
146 | ## Version 1.0
147 |
148 | * responders was removed from InheritedResources core and is a dependency. To install it, please do
149 |
150 | sudo gem install responders
151 |
152 | * has_scope was removed from InheritedResources core and is now available as a standalone gem
153 |
154 | To install it, please do
155 |
156 | sudo gem install has_scope
157 |
158 | ## Version 0.9
159 |
160 | * Allow dual blocks in destroy
161 | * Added :if and :unless to has_scope (thanks to Jack Danger)
162 | * Added create_resource, update_resource and delete_resource hooks (thanks to Carlos Antonio da Silva)
163 | * Backported ActionController::Responder from Rails 3
164 | * Added parent_url helper
165 | * Added association_chain helper (as suggested by https://github.com/emmanuel)
166 |
167 | ## Version 0.8
168 |
169 | * Fixed a small bug on optional belongs to with namespaced controllers
170 | * Allow a parameter to be given to collection_url in polymorphic cases to replace the parent
171 | * Allow InheritedResources to be called without inheritance
172 | * Ensure that controllers that inherit from a controller with InheritedResources works properly
173 |
174 | ## Version 0.7
175 |
176 | * Allow procs as default value in has scope to be able to use values from session, for example
177 | * Allow blocks with arity 0 or -1 to be given as the redirect url
178 |
179 | def destroy
180 | destroy!{ project_url(@project) }
181 | end
182 |
183 | * Allow interpolation_options to be set in the application controller
184 | * Added has_scope to controller (an interface for named_scopes)
185 | * Added polymorphic_belongs_to, optional_belongs_to and singleton_belongs_to as quick methods
186 | * Only load belongs_to, singleton and polymorphic helpers if they are actually required. base_helpers, class_methods, dumb_responder and url_helpers are loaded when you inherited from base for the first time
187 |
188 | # Version 0.6
189 |
190 | * Ensure that the default template is not rendered if the default_template_format is not accepted. This is somehow related with the security breach report
191 |
192 | https://rorsecurity.info/journal/2009/4/24/hidden-actions-render-templates.html
193 |
194 | IR forbids based on mime types. For example: respond_to :html, :except => :index ensures that the index.html.erb view is not rendered, making your IR controllers safer.
195 |
196 | * Fixed a bug that happens only when format.xml is given to blocks and then it acts as default, instead of format.html
197 | * Fixed a strange bug where when you have create.html.erb or update.html.erb, it makes IE6 and IE7 return unprocessable entity (because they send Mime::ALL)
198 | * Stop rescuing any error when constantizing the resource class and allow route_prefix to be nil
199 | * Cleaned up tests and responder structure. Whenever you pass a block to aliases and this block responds to the request, the other blocks are not parsed improving performance
200 | * [BACKWARDS INCOMPATIBLE] By default, Inherited Resources respond only :html requests
201 | * Added a quick way to overwrite the redirect to url in :create, :update and :destroy
202 |
203 | ## Version 0.5
204 |
205 | * Decoupled routes name from :instance_name and :collection_name. This way we have more flexibility. Use route_instance_name and route_collection_name to to change routes
206 | * Avoid calling human_name on nil when a resource class is not defined
207 | * Only call I18n if it's defined
208 |
209 | ## Version 0.4
210 |
211 | * Dealing with namespaced controllers out of the box
212 | * Added support to namespaced routes through :route_prefix
213 | * Added fix when resource_url is not defined
214 | * Added better handling for namespaced controllers
215 | * Added flash messages scoped by namespaced controllers
216 | * Deprecated {{resource}} in I18n, use {{resource_name}} instead
217 | * rspec bug fix is not automatically required anymore. User has to do it explicitly
218 | * Added a file which fix a rspec bug when render is called inside a method which receives a block
219 | * parent? does not take begin_of_association_chain into account anymore
220 | * Added options to url helpers
221 | * Added :optional to belongs_to associations. It allows you to deal with categories/1/products/2 and /products/2 with just one controller
222 | * Cleaned up tests
223 |
224 | ## Version 0.3
225 |
226 | * Minor bump after three bug fixes
227 | * Bug fix when showing warning of constant redefinition
228 | * Bug fix with ApplicationController not being unloaded properly on development
229 | * Bug fix when having root singleton resources. Calling `collection_url` would raise "NoMethodError \_url", not it will call root_url
230 | * More comments on UrlHelpers
231 |
232 | ## Version 0.2
233 |
234 | * Bug fix when ApplicationController is already loaded when we load respond_to
235 | * Added support success/failure blocks
236 | * Eager loading of files to work properly in multithreaded environments
237 |
238 | ## Version 0.1
239 |
240 | * Added more helper_methods
241 | * Added Rails 2.3.0 and changed tests to work with ActionController::TestCase
242 | * First release. Support to I18n, singleton controllers, polymorphic controllers, belongs_to, nested_belongs_to and url helpers
243 |
244 | [#873]: https://github.com/activeadmin/inherited_resources/pull/873
245 | [#903]: https://github.com/activeadmin/inherited_resources/pull/903
246 | [#918]: https://github.com/activeadmin/inherited_resources/pull/918
247 | [#921]: https://github.com/activeadmin/inherited_resources/pull/921
248 | [#933]: https://github.com/activeadmin/inherited_resources/pull/933
249 | [#939]: https://github.com/activeadmin/inherited_resources/pull/939
250 | [#942]: https://github.com/activeadmin/inherited_resources/pull/942
251 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source 'https://rubygems.org'
3 |
4 | gemspec path: '.'
5 |
6 | group :development do
7 | gem 'rails', '~> 8.0.0'
8 |
9 | gem 'mocha'
10 | gem 'minitest'
11 | gem 'minitest-reporters'
12 | gem 'rails-controller-testing'
13 | gem 'simplecov', require: false
14 | gem 'simplecov-cobertura'
15 | gem 'warning'
16 | end
17 |
18 | group :rubocop do
19 | gem 'rubocop'
20 | gem 'rubocop-minitest'
21 | gem 'rubocop-packaging'
22 | gem 'rubocop-performance'
23 | end
24 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | inherited_resources (2.1.0)
5 | actionpack (>= 7.0)
6 | has_scope (>= 0.6)
7 | railties (>= 7.0)
8 | responders (>= 2)
9 |
10 | GEM
11 | remote: https://rubygems.org/
12 | specs:
13 | actioncable (8.0.2)
14 | actionpack (= 8.0.2)
15 | activesupport (= 8.0.2)
16 | nio4r (~> 2.0)
17 | websocket-driver (>= 0.6.1)
18 | zeitwerk (~> 2.6)
19 | actionmailbox (8.0.2)
20 | actionpack (= 8.0.2)
21 | activejob (= 8.0.2)
22 | activerecord (= 8.0.2)
23 | activestorage (= 8.0.2)
24 | activesupport (= 8.0.2)
25 | mail (>= 2.8.0)
26 | actionmailer (8.0.2)
27 | actionpack (= 8.0.2)
28 | actionview (= 8.0.2)
29 | activejob (= 8.0.2)
30 | activesupport (= 8.0.2)
31 | mail (>= 2.8.0)
32 | rails-dom-testing (~> 2.2)
33 | actionpack (8.0.2)
34 | actionview (= 8.0.2)
35 | activesupport (= 8.0.2)
36 | nokogiri (>= 1.8.5)
37 | rack (>= 2.2.4)
38 | rack-session (>= 1.0.1)
39 | rack-test (>= 0.6.3)
40 | rails-dom-testing (~> 2.2)
41 | rails-html-sanitizer (~> 1.6)
42 | useragent (~> 0.16)
43 | actiontext (8.0.2)
44 | actionpack (= 8.0.2)
45 | activerecord (= 8.0.2)
46 | activestorage (= 8.0.2)
47 | activesupport (= 8.0.2)
48 | globalid (>= 0.6.0)
49 | nokogiri (>= 1.8.5)
50 | actionview (8.0.2)
51 | activesupport (= 8.0.2)
52 | builder (~> 3.1)
53 | erubi (~> 1.11)
54 | rails-dom-testing (~> 2.2)
55 | rails-html-sanitizer (~> 1.6)
56 | activejob (8.0.2)
57 | activesupport (= 8.0.2)
58 | globalid (>= 0.3.6)
59 | activemodel (8.0.2)
60 | activesupport (= 8.0.2)
61 | activerecord (8.0.2)
62 | activemodel (= 8.0.2)
63 | activesupport (= 8.0.2)
64 | timeout (>= 0.4.0)
65 | activestorage (8.0.2)
66 | actionpack (= 8.0.2)
67 | activejob (= 8.0.2)
68 | activerecord (= 8.0.2)
69 | activesupport (= 8.0.2)
70 | marcel (~> 1.0)
71 | activesupport (8.0.2)
72 | base64
73 | benchmark (>= 0.3)
74 | bigdecimal
75 | concurrent-ruby (~> 1.0, >= 1.3.1)
76 | connection_pool (>= 2.2.5)
77 | drb
78 | i18n (>= 1.6, < 2)
79 | logger (>= 1.4.2)
80 | minitest (>= 5.1)
81 | securerandom (>= 0.3)
82 | tzinfo (~> 2.0, >= 2.0.5)
83 | uri (>= 0.13.1)
84 | ansi (1.5.0)
85 | ast (2.4.3)
86 | base64 (0.2.0)
87 | benchmark (0.4.0)
88 | bigdecimal (3.1.9)
89 | builder (3.3.0)
90 | concurrent-ruby (1.3.5)
91 | connection_pool (2.5.3)
92 | crass (1.0.6)
93 | date (3.4.1)
94 | docile (1.4.1)
95 | drb (2.2.1)
96 | erubi (1.13.1)
97 | globalid (1.2.1)
98 | activesupport (>= 6.1)
99 | has_scope (0.8.2)
100 | actionpack (>= 5.2)
101 | activesupport (>= 5.2)
102 | i18n (1.14.7)
103 | concurrent-ruby (~> 1.0)
104 | io-console (0.8.0)
105 | irb (1.15.2)
106 | pp (>= 0.6.0)
107 | rdoc (>= 4.0.0)
108 | reline (>= 0.4.2)
109 | json (2.11.3)
110 | language_server-protocol (3.17.0.4)
111 | lint_roller (1.1.0)
112 | logger (1.7.0)
113 | loofah (2.24.0)
114 | crass (~> 1.0.2)
115 | nokogiri (>= 1.12.0)
116 | mail (2.8.1)
117 | mini_mime (>= 0.1.1)
118 | net-imap
119 | net-pop
120 | net-smtp
121 | marcel (1.0.4)
122 | mini_mime (1.1.5)
123 | mini_portile2 (2.8.8)
124 | minitest (5.25.5)
125 | minitest-reporters (1.7.1)
126 | ansi
127 | builder
128 | minitest (>= 5.0)
129 | ruby-progressbar
130 | mocha (2.7.1)
131 | ruby2_keywords (>= 0.0.5)
132 | net-imap (0.5.7)
133 | date
134 | net-protocol
135 | net-pop (0.1.2)
136 | net-protocol
137 | net-protocol (0.2.2)
138 | timeout
139 | net-smtp (0.5.1)
140 | net-protocol
141 | nio4r (2.7.4)
142 | nokogiri (1.18.8)
143 | mini_portile2 (~> 2.8.2)
144 | racc (~> 1.4)
145 | nokogiri (1.18.8-aarch64-linux-gnu)
146 | racc (~> 1.4)
147 | nokogiri (1.18.8-arm64-darwin)
148 | racc (~> 1.4)
149 | nokogiri (1.18.8-x86_64-darwin)
150 | racc (~> 1.4)
151 | nokogiri (1.18.8-x86_64-linux-gnu)
152 | racc (~> 1.4)
153 | parallel (1.27.0)
154 | parser (3.3.8.0)
155 | ast (~> 2.4.1)
156 | racc
157 | pp (0.6.2)
158 | prettyprint
159 | prettyprint (0.2.0)
160 | prism (1.4.0)
161 | psych (5.2.3)
162 | date
163 | stringio
164 | racc (1.8.1)
165 | rack (3.1.13)
166 | rack-session (2.1.0)
167 | base64 (>= 0.1.0)
168 | rack (>= 3.0.0)
169 | rack-test (2.2.0)
170 | rack (>= 1.3)
171 | rackup (2.2.1)
172 | rack (>= 3)
173 | rails (8.0.2)
174 | actioncable (= 8.0.2)
175 | actionmailbox (= 8.0.2)
176 | actionmailer (= 8.0.2)
177 | actionpack (= 8.0.2)
178 | actiontext (= 8.0.2)
179 | actionview (= 8.0.2)
180 | activejob (= 8.0.2)
181 | activemodel (= 8.0.2)
182 | activerecord (= 8.0.2)
183 | activestorage (= 8.0.2)
184 | activesupport (= 8.0.2)
185 | bundler (>= 1.15.0)
186 | railties (= 8.0.2)
187 | rails-controller-testing (1.0.5)
188 | actionpack (>= 5.0.1.rc1)
189 | actionview (>= 5.0.1.rc1)
190 | activesupport (>= 5.0.1.rc1)
191 | rails-dom-testing (2.2.0)
192 | activesupport (>= 5.0.0)
193 | minitest
194 | nokogiri (>= 1.6)
195 | rails-html-sanitizer (1.6.2)
196 | loofah (~> 2.21)
197 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
198 | railties (8.0.2)
199 | actionpack (= 8.0.2)
200 | activesupport (= 8.0.2)
201 | irb (~> 1.13)
202 | rackup (>= 1.0.0)
203 | rake (>= 12.2)
204 | thor (~> 1.0, >= 1.2.2)
205 | zeitwerk (~> 2.6)
206 | rainbow (3.1.1)
207 | rake (13.2.1)
208 | rdoc (6.13.1)
209 | psych (>= 4.0.0)
210 | regexp_parser (2.10.0)
211 | reline (0.6.1)
212 | io-console (~> 0.5)
213 | responders (3.1.1)
214 | actionpack (>= 5.2)
215 | railties (>= 5.2)
216 | rexml (3.4.1)
217 | rubocop (1.75.4)
218 | json (~> 2.3)
219 | language_server-protocol (~> 3.17.0.2)
220 | lint_roller (~> 1.1.0)
221 | parallel (~> 1.10)
222 | parser (>= 3.3.0.2)
223 | rainbow (>= 2.2.2, < 4.0)
224 | regexp_parser (>= 2.9.3, < 3.0)
225 | rubocop-ast (>= 1.44.0, < 2.0)
226 | ruby-progressbar (~> 1.7)
227 | unicode-display_width (>= 2.4.0, < 4.0)
228 | rubocop-ast (1.44.1)
229 | parser (>= 3.3.7.2)
230 | prism (~> 1.4)
231 | rubocop-minitest (0.38.0)
232 | lint_roller (~> 1.1)
233 | rubocop (>= 1.75.0, < 2.0)
234 | rubocop-ast (>= 1.38.0, < 2.0)
235 | rubocop-packaging (0.6.0)
236 | lint_roller (~> 1.1.0)
237 | rubocop (>= 1.72.1, < 2.0)
238 | rubocop-performance (1.25.0)
239 | lint_roller (~> 1.1)
240 | rubocop (>= 1.75.0, < 2.0)
241 | rubocop-ast (>= 1.38.0, < 2.0)
242 | ruby-progressbar (1.13.0)
243 | ruby2_keywords (0.0.5)
244 | securerandom (0.4.1)
245 | simplecov (0.22.0)
246 | docile (~> 1.1)
247 | simplecov-html (~> 0.11)
248 | simplecov_json_formatter (~> 0.1)
249 | simplecov-cobertura (2.1.0)
250 | rexml
251 | simplecov (~> 0.19)
252 | simplecov-html (0.13.1)
253 | simplecov_json_formatter (0.1.4)
254 | stringio (3.1.7)
255 | thor (1.3.2)
256 | timeout (0.4.3)
257 | tzinfo (2.0.6)
258 | concurrent-ruby (~> 1.0)
259 | unicode-display_width (3.1.4)
260 | unicode-emoji (~> 4.0, >= 4.0.4)
261 | unicode-emoji (4.0.4)
262 | uri (1.0.3)
263 | useragent (0.16.11)
264 | warning (1.5.0)
265 | websocket-driver (0.7.7)
266 | base64
267 | websocket-extensions (>= 0.1.0)
268 | websocket-extensions (0.1.5)
269 | zeitwerk (2.7.2)
270 |
271 | PLATFORMS
272 | aarch64-linux
273 | arm64-darwin
274 | ruby
275 | x86_64-darwin
276 | x86_64-linux
277 |
278 | DEPENDENCIES
279 | inherited_resources!
280 | minitest
281 | minitest-reporters
282 | mocha
283 | rails (~> 8.0.0)
284 | rails-controller-testing
285 | rubocop
286 | rubocop-minitest
287 | rubocop-packaging
288 | rubocop-performance
289 | simplecov
290 | simplecov-cobertura
291 | warning
292 |
293 | BUNDLED WITH
294 | 2.6.8
295 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2017 José Valim
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'bundler/gem_tasks'
3 | require 'rake/testtask'
4 | require 'rdoc/task'
5 |
6 | desc 'Run tests for InheritedResources.'
7 | Rake::TestTask.new(:test) do |t|
8 | t.pattern = "test/**/*_test.rb"
9 | t.libs << "test"
10 | t.libs << "lib"
11 | t.verbose = true
12 | end
13 |
14 | desc 'Generate documentation for InheritedResources.'
15 | Rake::RDocTask.new(:rdoc) do |rdoc|
16 | rdoc.rdoc_dir = 'rdoc'
17 | rdoc.title = 'InheritedResources'
18 | rdoc.options << '--line-numbers' << '--inline-source'
19 | rdoc.rdoc_files.include('README.rdoc')
20 | rdoc.rdoc_files.include('MIT-LICENSE')
21 | rdoc.rdoc_files.include('lib/**/*.rb')
22 | end
23 |
24 | task :rubocop do
25 | sh('bin/rubocop')
26 | end
27 |
28 | task default: [:test, :rubocop]
29 |
--------------------------------------------------------------------------------
/app/controllers/inherited_resources/base.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module InheritedResources
3 | # = Base
4 | #
5 | # This is the base class that holds all actions. If you see the code for each
6 | # action, they are quite similar to Rails default scaffold.
7 | #
8 | # To change your base behavior, you can overwrite your actions and call super,
9 | # call default class method, call <actions class method
10 | # or overwrite some helpers in the base_helpers.rb file.
11 | #
12 | class Base < InheritedResources.parent_controller.constantize
13 | # Overwrite inherit_resources to add specific InheritedResources behavior.
14 | def self.inherit_resources(base)
15 | base.class_eval do
16 | include InheritedResources::Actions
17 | include InheritedResources::BaseHelpers
18 | extend InheritedResources::ClassMethods
19 | extend InheritedResources::UrlHelpers
20 |
21 | # Add at least :html mime type
22 | respond_to :html if self.mimes_for_respond_to.empty?
23 | self.responder = InheritedResources::Responder
24 |
25 | helper_method :resource, :collection, :resource_class, :association_chain,
26 | :resource_instance_name, :resource_collection_name,
27 | :resource_url, :resource_path,
28 | :collection_url, :collection_path,
29 | :new_resource_url, :new_resource_path,
30 | :edit_resource_url, :edit_resource_path,
31 | :parent_url, :parent_path,
32 | :smart_resource_url, :smart_collection_url
33 |
34 | self.class_attribute :resource_class, instance_writer: false unless self.respond_to? :resource_class
35 | self.class_attribute :parents_symbols, :resources_configuration, instance_writer: false
36 |
37 | protected :resource_class, :parents_symbols, :resources_configuration,
38 | :resource_class?, :parents_symbols?, :resources_configuration?
39 | end
40 | end
41 |
42 | inherit_resources(self)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ( set -x; bundle $@ )
4 |
5 | for gemfile in gemfiles/*/Gemfile; do
6 | ( set -x; BUNDLE_GEMFILE="$gemfile" bundle $@ )
7 | done
8 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | #
5 | # This file was generated by Bundler.
6 | #
7 | # The application 'rake' is installed as part of a gem, and
8 | # this file is here to facilitate running it.
9 | #
10 |
11 | require "pathname"
12 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13 | Pathname.new(__FILE__).realpath)
14 |
15 | bundle_binstub = File.expand_path("../bundle", __FILE__)
16 |
17 | if File.file?(bundle_binstub)
18 | if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
19 | load(bundle_binstub)
20 | else
21 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23 | end
24 | end
25 |
26 | require "rubygems"
27 | require "bundler/setup"
28 |
29 | load Gem.bin_path("rake", "rake")
30 |
--------------------------------------------------------------------------------
/bin/rubocop:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 |
4 | ENV["BUNDLE_GEMFILE"] = File.expand_path("../Gemfile", __dir__)
5 |
6 | require "bundler/setup"
7 |
8 | load Gem.bin_path("rubocop", "rubocop")
9 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | threshold: 0.05%
6 |
--------------------------------------------------------------------------------
/gemfiles/rails_70/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source 'https://rubygems.org'
3 |
4 | gemspec path: '../..'
5 |
6 | group :development do
7 | gem 'rails', '~> 7.0.0'
8 |
9 | gem 'mocha'
10 | gem 'minitest'
11 | gem 'minitest-reporters'
12 | gem 'rails-controller-testing'
13 | gem 'simplecov', require: false
14 | gem 'simplecov-cobertura'
15 | gem 'warning'
16 |
17 | gem "concurrent-ruby", "1.3.4" # Ref: rails/rails#54260
18 |
19 | # FIXME: relax this dependency when Ruby 3.1 support will be dropped
20 | gem "zeitwerk", "~> 2.6.18"
21 | end
22 |
--------------------------------------------------------------------------------
/gemfiles/rails_70/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: ../..
3 | specs:
4 | inherited_resources (2.1.0)
5 | actionpack (>= 7.0)
6 | has_scope (>= 0.6)
7 | railties (>= 7.0)
8 | responders (>= 2)
9 |
10 | GEM
11 | remote: https://rubygems.org/
12 | specs:
13 | actioncable (7.0.8.7)
14 | actionpack (= 7.0.8.7)
15 | activesupport (= 7.0.8.7)
16 | nio4r (~> 2.0)
17 | websocket-driver (>= 0.6.1)
18 | actionmailbox (7.0.8.7)
19 | actionpack (= 7.0.8.7)
20 | activejob (= 7.0.8.7)
21 | activerecord (= 7.0.8.7)
22 | activestorage (= 7.0.8.7)
23 | activesupport (= 7.0.8.7)
24 | mail (>= 2.7.1)
25 | net-imap
26 | net-pop
27 | net-smtp
28 | actionmailer (7.0.8.7)
29 | actionpack (= 7.0.8.7)
30 | actionview (= 7.0.8.7)
31 | activejob (= 7.0.8.7)
32 | activesupport (= 7.0.8.7)
33 | mail (~> 2.5, >= 2.5.4)
34 | net-imap
35 | net-pop
36 | net-smtp
37 | rails-dom-testing (~> 2.0)
38 | actionpack (7.0.8.7)
39 | actionview (= 7.0.8.7)
40 | activesupport (= 7.0.8.7)
41 | rack (~> 2.0, >= 2.2.4)
42 | rack-test (>= 0.6.3)
43 | rails-dom-testing (~> 2.0)
44 | rails-html-sanitizer (~> 1.0, >= 1.2.0)
45 | actiontext (7.0.8.7)
46 | actionpack (= 7.0.8.7)
47 | activerecord (= 7.0.8.7)
48 | activestorage (= 7.0.8.7)
49 | activesupport (= 7.0.8.7)
50 | globalid (>= 0.6.0)
51 | nokogiri (>= 1.8.5)
52 | actionview (7.0.8.7)
53 | activesupport (= 7.0.8.7)
54 | builder (~> 3.1)
55 | erubi (~> 1.4)
56 | rails-dom-testing (~> 2.0)
57 | rails-html-sanitizer (~> 1.1, >= 1.2.0)
58 | activejob (7.0.8.7)
59 | activesupport (= 7.0.8.7)
60 | globalid (>= 0.3.6)
61 | activemodel (7.0.8.7)
62 | activesupport (= 7.0.8.7)
63 | activerecord (7.0.8.7)
64 | activemodel (= 7.0.8.7)
65 | activesupport (= 7.0.8.7)
66 | activestorage (7.0.8.7)
67 | actionpack (= 7.0.8.7)
68 | activejob (= 7.0.8.7)
69 | activerecord (= 7.0.8.7)
70 | activesupport (= 7.0.8.7)
71 | marcel (~> 1.0)
72 | mini_mime (>= 1.1.0)
73 | activesupport (7.0.8.7)
74 | concurrent-ruby (~> 1.0, >= 1.0.2)
75 | i18n (>= 1.6, < 2)
76 | minitest (>= 5.1)
77 | tzinfo (~> 2.0)
78 | ansi (1.5.0)
79 | base64 (0.2.0)
80 | builder (3.3.0)
81 | concurrent-ruby (1.3.4)
82 | crass (1.0.6)
83 | date (3.4.1)
84 | docile (1.4.1)
85 | erubi (1.13.1)
86 | globalid (1.2.1)
87 | activesupport (>= 6.1)
88 | has_scope (0.8.2)
89 | actionpack (>= 5.2)
90 | activesupport (>= 5.2)
91 | i18n (1.14.7)
92 | concurrent-ruby (~> 1.0)
93 | loofah (2.24.0)
94 | crass (~> 1.0.2)
95 | nokogiri (>= 1.12.0)
96 | mail (2.8.1)
97 | mini_mime (>= 0.1.1)
98 | net-imap
99 | net-pop
100 | net-smtp
101 | marcel (1.0.4)
102 | method_source (1.1.0)
103 | mini_mime (1.1.5)
104 | mini_portile2 (2.8.8)
105 | minitest (5.25.5)
106 | minitest-reporters (1.7.1)
107 | ansi
108 | builder
109 | minitest (>= 5.0)
110 | ruby-progressbar
111 | mocha (2.7.1)
112 | ruby2_keywords (>= 0.0.5)
113 | net-imap (0.5.7)
114 | date
115 | net-protocol
116 | net-pop (0.1.2)
117 | net-protocol
118 | net-protocol (0.2.2)
119 | timeout
120 | net-smtp (0.5.1)
121 | net-protocol
122 | nio4r (2.7.4)
123 | nokogiri (1.18.8)
124 | mini_portile2 (~> 2.8.2)
125 | racc (~> 1.4)
126 | nokogiri (1.18.8-aarch64-linux-gnu)
127 | racc (~> 1.4)
128 | nokogiri (1.18.8-arm64-darwin)
129 | racc (~> 1.4)
130 | nokogiri (1.18.8-x86_64-darwin)
131 | racc (~> 1.4)
132 | nokogiri (1.18.8-x86_64-linux-gnu)
133 | racc (~> 1.4)
134 | racc (1.8.1)
135 | rack (2.2.13)
136 | rack-test (2.2.0)
137 | rack (>= 1.3)
138 | rails (7.0.8.7)
139 | actioncable (= 7.0.8.7)
140 | actionmailbox (= 7.0.8.7)
141 | actionmailer (= 7.0.8.7)
142 | actionpack (= 7.0.8.7)
143 | actiontext (= 7.0.8.7)
144 | actionview (= 7.0.8.7)
145 | activejob (= 7.0.8.7)
146 | activemodel (= 7.0.8.7)
147 | activerecord (= 7.0.8.7)
148 | activestorage (= 7.0.8.7)
149 | activesupport (= 7.0.8.7)
150 | bundler (>= 1.15.0)
151 | railties (= 7.0.8.7)
152 | rails-controller-testing (1.0.5)
153 | actionpack (>= 5.0.1.rc1)
154 | actionview (>= 5.0.1.rc1)
155 | activesupport (>= 5.0.1.rc1)
156 | rails-dom-testing (2.2.0)
157 | activesupport (>= 5.0.0)
158 | minitest
159 | nokogiri (>= 1.6)
160 | rails-html-sanitizer (1.6.2)
161 | loofah (~> 2.21)
162 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
163 | railties (7.0.8.7)
164 | actionpack (= 7.0.8.7)
165 | activesupport (= 7.0.8.7)
166 | method_source
167 | rake (>= 12.2)
168 | thor (~> 1.0)
169 | zeitwerk (~> 2.5)
170 | rake (13.2.1)
171 | responders (3.1.1)
172 | actionpack (>= 5.2)
173 | railties (>= 5.2)
174 | rexml (3.4.1)
175 | ruby-progressbar (1.13.0)
176 | ruby2_keywords (0.0.5)
177 | simplecov (0.22.0)
178 | docile (~> 1.1)
179 | simplecov-html (~> 0.11)
180 | simplecov_json_formatter (~> 0.1)
181 | simplecov-cobertura (2.1.0)
182 | rexml
183 | simplecov (~> 0.19)
184 | simplecov-html (0.13.1)
185 | simplecov_json_formatter (0.1.4)
186 | thor (1.3.2)
187 | timeout (0.4.3)
188 | tzinfo (2.0.6)
189 | concurrent-ruby (~> 1.0)
190 | warning (1.5.0)
191 | websocket-driver (0.7.7)
192 | base64
193 | websocket-extensions (>= 0.1.0)
194 | websocket-extensions (0.1.5)
195 | zeitwerk (2.6.18)
196 |
197 | PLATFORMS
198 | aarch64-linux
199 | arm64-darwin
200 | ruby
201 | x86_64-darwin
202 | x86_64-linux
203 |
204 | DEPENDENCIES
205 | concurrent-ruby (= 1.3.4)
206 | inherited_resources!
207 | minitest
208 | minitest-reporters
209 | mocha
210 | rails (~> 7.0.0)
211 | rails-controller-testing
212 | simplecov
213 | simplecov-cobertura
214 | warning
215 | zeitwerk (~> 2.6.18)
216 |
217 | BUNDLED WITH
218 | 2.6.8
219 |
--------------------------------------------------------------------------------
/gemfiles/rails_71/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source 'https://rubygems.org'
3 |
4 | gemspec path: '../..'
5 |
6 | group :development do
7 | gem 'rails', '~> 7.1.0'
8 |
9 | gem 'mocha'
10 | gem 'minitest'
11 | gem 'minitest-reporters'
12 | gem 'rails-controller-testing'
13 | gem 'simplecov', require: false
14 | gem 'simplecov-cobertura'
15 | gem 'warning'
16 |
17 | # FIXME: relax this dependency when Ruby 3.1 support will be dropped
18 | gem "zeitwerk", "~> 2.6.18"
19 | end
20 |
--------------------------------------------------------------------------------
/gemfiles/rails_71/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: ../..
3 | specs:
4 | inherited_resources (2.1.0)
5 | actionpack (>= 7.0)
6 | has_scope (>= 0.6)
7 | railties (>= 7.0)
8 | responders (>= 2)
9 |
10 | GEM
11 | remote: https://rubygems.org/
12 | specs:
13 | actioncable (7.1.5.1)
14 | actionpack (= 7.1.5.1)
15 | activesupport (= 7.1.5.1)
16 | nio4r (~> 2.0)
17 | websocket-driver (>= 0.6.1)
18 | zeitwerk (~> 2.6)
19 | actionmailbox (7.1.5.1)
20 | actionpack (= 7.1.5.1)
21 | activejob (= 7.1.5.1)
22 | activerecord (= 7.1.5.1)
23 | activestorage (= 7.1.5.1)
24 | activesupport (= 7.1.5.1)
25 | mail (>= 2.7.1)
26 | net-imap
27 | net-pop
28 | net-smtp
29 | actionmailer (7.1.5.1)
30 | actionpack (= 7.1.5.1)
31 | actionview (= 7.1.5.1)
32 | activejob (= 7.1.5.1)
33 | activesupport (= 7.1.5.1)
34 | mail (~> 2.5, >= 2.5.4)
35 | net-imap
36 | net-pop
37 | net-smtp
38 | rails-dom-testing (~> 2.2)
39 | actionpack (7.1.5.1)
40 | actionview (= 7.1.5.1)
41 | activesupport (= 7.1.5.1)
42 | nokogiri (>= 1.8.5)
43 | racc
44 | rack (>= 2.2.4)
45 | rack-session (>= 1.0.1)
46 | rack-test (>= 0.6.3)
47 | rails-dom-testing (~> 2.2)
48 | rails-html-sanitizer (~> 1.6)
49 | actiontext (7.1.5.1)
50 | actionpack (= 7.1.5.1)
51 | activerecord (= 7.1.5.1)
52 | activestorage (= 7.1.5.1)
53 | activesupport (= 7.1.5.1)
54 | globalid (>= 0.6.0)
55 | nokogiri (>= 1.8.5)
56 | actionview (7.1.5.1)
57 | activesupport (= 7.1.5.1)
58 | builder (~> 3.1)
59 | erubi (~> 1.11)
60 | rails-dom-testing (~> 2.2)
61 | rails-html-sanitizer (~> 1.6)
62 | activejob (7.1.5.1)
63 | activesupport (= 7.1.5.1)
64 | globalid (>= 0.3.6)
65 | activemodel (7.1.5.1)
66 | activesupport (= 7.1.5.1)
67 | activerecord (7.1.5.1)
68 | activemodel (= 7.1.5.1)
69 | activesupport (= 7.1.5.1)
70 | timeout (>= 0.4.0)
71 | activestorage (7.1.5.1)
72 | actionpack (= 7.1.5.1)
73 | activejob (= 7.1.5.1)
74 | activerecord (= 7.1.5.1)
75 | activesupport (= 7.1.5.1)
76 | marcel (~> 1.0)
77 | activesupport (7.1.5.1)
78 | base64
79 | benchmark (>= 0.3)
80 | bigdecimal
81 | concurrent-ruby (~> 1.0, >= 1.0.2)
82 | connection_pool (>= 2.2.5)
83 | drb
84 | i18n (>= 1.6, < 2)
85 | logger (>= 1.4.2)
86 | minitest (>= 5.1)
87 | mutex_m
88 | securerandom (>= 0.3)
89 | tzinfo (~> 2.0)
90 | ansi (1.5.0)
91 | base64 (0.2.0)
92 | benchmark (0.4.0)
93 | bigdecimal (3.1.9)
94 | builder (3.3.0)
95 | concurrent-ruby (1.3.5)
96 | connection_pool (2.5.3)
97 | crass (1.0.6)
98 | date (3.4.1)
99 | docile (1.4.1)
100 | drb (2.2.1)
101 | erubi (1.13.1)
102 | globalid (1.2.1)
103 | activesupport (>= 6.1)
104 | has_scope (0.8.2)
105 | actionpack (>= 5.2)
106 | activesupport (>= 5.2)
107 | i18n (1.14.7)
108 | concurrent-ruby (~> 1.0)
109 | io-console (0.8.0)
110 | irb (1.15.2)
111 | pp (>= 0.6.0)
112 | rdoc (>= 4.0.0)
113 | reline (>= 0.4.2)
114 | logger (1.7.0)
115 | loofah (2.24.0)
116 | crass (~> 1.0.2)
117 | nokogiri (>= 1.12.0)
118 | mail (2.8.1)
119 | mini_mime (>= 0.1.1)
120 | net-imap
121 | net-pop
122 | net-smtp
123 | marcel (1.0.4)
124 | mini_mime (1.1.5)
125 | mini_portile2 (2.8.8)
126 | minitest (5.25.5)
127 | minitest-reporters (1.7.1)
128 | ansi
129 | builder
130 | minitest (>= 5.0)
131 | ruby-progressbar
132 | mocha (2.7.1)
133 | ruby2_keywords (>= 0.0.5)
134 | mutex_m (0.3.0)
135 | net-imap (0.5.7)
136 | date
137 | net-protocol
138 | net-pop (0.1.2)
139 | net-protocol
140 | net-protocol (0.2.2)
141 | timeout
142 | net-smtp (0.5.1)
143 | net-protocol
144 | nio4r (2.7.4)
145 | nokogiri (1.18.8)
146 | mini_portile2 (~> 2.8.2)
147 | racc (~> 1.4)
148 | nokogiri (1.18.8-aarch64-linux-gnu)
149 | racc (~> 1.4)
150 | nokogiri (1.18.8-arm64-darwin)
151 | racc (~> 1.4)
152 | nokogiri (1.18.8-x86_64-darwin)
153 | racc (~> 1.4)
154 | nokogiri (1.18.8-x86_64-linux-gnu)
155 | racc (~> 1.4)
156 | pp (0.6.2)
157 | prettyprint
158 | prettyprint (0.2.0)
159 | psych (5.2.3)
160 | date
161 | stringio
162 | racc (1.8.1)
163 | rack (3.1.13)
164 | rack-session (2.1.0)
165 | base64 (>= 0.1.0)
166 | rack (>= 3.0.0)
167 | rack-test (2.2.0)
168 | rack (>= 1.3)
169 | rackup (2.2.1)
170 | rack (>= 3)
171 | rails (7.1.5.1)
172 | actioncable (= 7.1.5.1)
173 | actionmailbox (= 7.1.5.1)
174 | actionmailer (= 7.1.5.1)
175 | actionpack (= 7.1.5.1)
176 | actiontext (= 7.1.5.1)
177 | actionview (= 7.1.5.1)
178 | activejob (= 7.1.5.1)
179 | activemodel (= 7.1.5.1)
180 | activerecord (= 7.1.5.1)
181 | activestorage (= 7.1.5.1)
182 | activesupport (= 7.1.5.1)
183 | bundler (>= 1.15.0)
184 | railties (= 7.1.5.1)
185 | rails-controller-testing (1.0.5)
186 | actionpack (>= 5.0.1.rc1)
187 | actionview (>= 5.0.1.rc1)
188 | activesupport (>= 5.0.1.rc1)
189 | rails-dom-testing (2.2.0)
190 | activesupport (>= 5.0.0)
191 | minitest
192 | nokogiri (>= 1.6)
193 | rails-html-sanitizer (1.6.2)
194 | loofah (~> 2.21)
195 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
196 | railties (7.1.5.1)
197 | actionpack (= 7.1.5.1)
198 | activesupport (= 7.1.5.1)
199 | irb
200 | rackup (>= 1.0.0)
201 | rake (>= 12.2)
202 | thor (~> 1.0, >= 1.2.2)
203 | zeitwerk (~> 2.6)
204 | rake (13.2.1)
205 | rdoc (6.13.1)
206 | psych (>= 4.0.0)
207 | reline (0.6.1)
208 | io-console (~> 0.5)
209 | responders (3.1.1)
210 | actionpack (>= 5.2)
211 | railties (>= 5.2)
212 | rexml (3.4.1)
213 | ruby-progressbar (1.13.0)
214 | ruby2_keywords (0.0.5)
215 | securerandom (0.4.1)
216 | simplecov (0.22.0)
217 | docile (~> 1.1)
218 | simplecov-html (~> 0.11)
219 | simplecov_json_formatter (~> 0.1)
220 | simplecov-cobertura (2.1.0)
221 | rexml
222 | simplecov (~> 0.19)
223 | simplecov-html (0.13.1)
224 | simplecov_json_formatter (0.1.4)
225 | stringio (3.1.7)
226 | thor (1.3.2)
227 | timeout (0.4.3)
228 | tzinfo (2.0.6)
229 | concurrent-ruby (~> 1.0)
230 | warning (1.5.0)
231 | websocket-driver (0.7.7)
232 | base64
233 | websocket-extensions (>= 0.1.0)
234 | websocket-extensions (0.1.5)
235 | zeitwerk (2.6.18)
236 |
237 | PLATFORMS
238 | aarch64-linux
239 | arm64-darwin
240 | ruby
241 | x86_64-darwin
242 | x86_64-linux
243 |
244 | DEPENDENCIES
245 | inherited_resources!
246 | minitest
247 | minitest-reporters
248 | mocha
249 | rails (~> 7.1.0)
250 | rails-controller-testing
251 | simplecov
252 | simplecov-cobertura
253 | warning
254 | zeitwerk (~> 2.6.18)
255 |
256 | BUNDLED WITH
257 | 2.6.8
258 |
--------------------------------------------------------------------------------
/gemfiles/rails_72/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | source 'https://rubygems.org'
3 |
4 | gemspec path: '../..'
5 |
6 | group :development do
7 | gem 'rails', '~> 7.2.0'
8 |
9 | gem 'mocha'
10 | gem 'minitest'
11 | gem 'minitest-reporters'
12 | gem 'rails-controller-testing'
13 | gem 'simplecov', require: false
14 | gem 'simplecov-cobertura'
15 | gem 'warning'
16 |
17 | # FIXME: relax this dependency when Ruby 3.1 support will be dropped
18 | gem "zeitwerk", "~> 2.6.18"
19 | end
20 |
--------------------------------------------------------------------------------
/gemfiles/rails_72/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: ../..
3 | specs:
4 | inherited_resources (2.1.0)
5 | actionpack (>= 7.0)
6 | has_scope (>= 0.6)
7 | railties (>= 7.0)
8 | responders (>= 2)
9 |
10 | GEM
11 | remote: https://rubygems.org/
12 | specs:
13 | actioncable (7.2.2.1)
14 | actionpack (= 7.2.2.1)
15 | activesupport (= 7.2.2.1)
16 | nio4r (~> 2.0)
17 | websocket-driver (>= 0.6.1)
18 | zeitwerk (~> 2.6)
19 | actionmailbox (7.2.2.1)
20 | actionpack (= 7.2.2.1)
21 | activejob (= 7.2.2.1)
22 | activerecord (= 7.2.2.1)
23 | activestorage (= 7.2.2.1)
24 | activesupport (= 7.2.2.1)
25 | mail (>= 2.8.0)
26 | actionmailer (7.2.2.1)
27 | actionpack (= 7.2.2.1)
28 | actionview (= 7.2.2.1)
29 | activejob (= 7.2.2.1)
30 | activesupport (= 7.2.2.1)
31 | mail (>= 2.8.0)
32 | rails-dom-testing (~> 2.2)
33 | actionpack (7.2.2.1)
34 | actionview (= 7.2.2.1)
35 | activesupport (= 7.2.2.1)
36 | nokogiri (>= 1.8.5)
37 | racc
38 | rack (>= 2.2.4, < 3.2)
39 | rack-session (>= 1.0.1)
40 | rack-test (>= 0.6.3)
41 | rails-dom-testing (~> 2.2)
42 | rails-html-sanitizer (~> 1.6)
43 | useragent (~> 0.16)
44 | actiontext (7.2.2.1)
45 | actionpack (= 7.2.2.1)
46 | activerecord (= 7.2.2.1)
47 | activestorage (= 7.2.2.1)
48 | activesupport (= 7.2.2.1)
49 | globalid (>= 0.6.0)
50 | nokogiri (>= 1.8.5)
51 | actionview (7.2.2.1)
52 | activesupport (= 7.2.2.1)
53 | builder (~> 3.1)
54 | erubi (~> 1.11)
55 | rails-dom-testing (~> 2.2)
56 | rails-html-sanitizer (~> 1.6)
57 | activejob (7.2.2.1)
58 | activesupport (= 7.2.2.1)
59 | globalid (>= 0.3.6)
60 | activemodel (7.2.2.1)
61 | activesupport (= 7.2.2.1)
62 | activerecord (7.2.2.1)
63 | activemodel (= 7.2.2.1)
64 | activesupport (= 7.2.2.1)
65 | timeout (>= 0.4.0)
66 | activestorage (7.2.2.1)
67 | actionpack (= 7.2.2.1)
68 | activejob (= 7.2.2.1)
69 | activerecord (= 7.2.2.1)
70 | activesupport (= 7.2.2.1)
71 | marcel (~> 1.0)
72 | activesupport (7.2.2.1)
73 | base64
74 | benchmark (>= 0.3)
75 | bigdecimal
76 | concurrent-ruby (~> 1.0, >= 1.3.1)
77 | connection_pool (>= 2.2.5)
78 | drb
79 | i18n (>= 1.6, < 2)
80 | logger (>= 1.4.2)
81 | minitest (>= 5.1)
82 | securerandom (>= 0.3)
83 | tzinfo (~> 2.0, >= 2.0.5)
84 | ansi (1.5.0)
85 | base64 (0.2.0)
86 | benchmark (0.4.0)
87 | bigdecimal (3.1.9)
88 | builder (3.3.0)
89 | concurrent-ruby (1.3.5)
90 | connection_pool (2.5.3)
91 | crass (1.0.6)
92 | date (3.4.1)
93 | docile (1.4.1)
94 | drb (2.2.1)
95 | erubi (1.13.1)
96 | globalid (1.2.1)
97 | activesupport (>= 6.1)
98 | has_scope (0.8.2)
99 | actionpack (>= 5.2)
100 | activesupport (>= 5.2)
101 | i18n (1.14.7)
102 | concurrent-ruby (~> 1.0)
103 | io-console (0.8.0)
104 | irb (1.15.2)
105 | pp (>= 0.6.0)
106 | rdoc (>= 4.0.0)
107 | reline (>= 0.4.2)
108 | logger (1.7.0)
109 | loofah (2.24.0)
110 | crass (~> 1.0.2)
111 | nokogiri (>= 1.12.0)
112 | mail (2.8.1)
113 | mini_mime (>= 0.1.1)
114 | net-imap
115 | net-pop
116 | net-smtp
117 | marcel (1.0.4)
118 | mini_mime (1.1.5)
119 | mini_portile2 (2.8.8)
120 | minitest (5.25.5)
121 | minitest-reporters (1.7.1)
122 | ansi
123 | builder
124 | minitest (>= 5.0)
125 | ruby-progressbar
126 | mocha (2.7.1)
127 | ruby2_keywords (>= 0.0.5)
128 | net-imap (0.5.7)
129 | date
130 | net-protocol
131 | net-pop (0.1.2)
132 | net-protocol
133 | net-protocol (0.2.2)
134 | timeout
135 | net-smtp (0.5.1)
136 | net-protocol
137 | nio4r (2.7.4)
138 | nokogiri (1.18.8)
139 | mini_portile2 (~> 2.8.2)
140 | racc (~> 1.4)
141 | nokogiri (1.18.8-aarch64-linux-gnu)
142 | racc (~> 1.4)
143 | nokogiri (1.18.8-arm64-darwin)
144 | racc (~> 1.4)
145 | nokogiri (1.18.8-x86_64-darwin)
146 | racc (~> 1.4)
147 | nokogiri (1.18.8-x86_64-linux-gnu)
148 | racc (~> 1.4)
149 | pp (0.6.2)
150 | prettyprint
151 | prettyprint (0.2.0)
152 | psych (5.2.3)
153 | date
154 | stringio
155 | racc (1.8.1)
156 | rack (3.1.13)
157 | rack-session (2.1.0)
158 | base64 (>= 0.1.0)
159 | rack (>= 3.0.0)
160 | rack-test (2.2.0)
161 | rack (>= 1.3)
162 | rackup (2.2.1)
163 | rack (>= 3)
164 | rails (7.2.2.1)
165 | actioncable (= 7.2.2.1)
166 | actionmailbox (= 7.2.2.1)
167 | actionmailer (= 7.2.2.1)
168 | actionpack (= 7.2.2.1)
169 | actiontext (= 7.2.2.1)
170 | actionview (= 7.2.2.1)
171 | activejob (= 7.2.2.1)
172 | activemodel (= 7.2.2.1)
173 | activerecord (= 7.2.2.1)
174 | activestorage (= 7.2.2.1)
175 | activesupport (= 7.2.2.1)
176 | bundler (>= 1.15.0)
177 | railties (= 7.2.2.1)
178 | rails-controller-testing (1.0.5)
179 | actionpack (>= 5.0.1.rc1)
180 | actionview (>= 5.0.1.rc1)
181 | activesupport (>= 5.0.1.rc1)
182 | rails-dom-testing (2.2.0)
183 | activesupport (>= 5.0.0)
184 | minitest
185 | nokogiri (>= 1.6)
186 | rails-html-sanitizer (1.6.2)
187 | loofah (~> 2.21)
188 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
189 | railties (7.2.2.1)
190 | actionpack (= 7.2.2.1)
191 | activesupport (= 7.2.2.1)
192 | irb (~> 1.13)
193 | rackup (>= 1.0.0)
194 | rake (>= 12.2)
195 | thor (~> 1.0, >= 1.2.2)
196 | zeitwerk (~> 2.6)
197 | rake (13.2.1)
198 | rdoc (6.13.1)
199 | psych (>= 4.0.0)
200 | reline (0.6.1)
201 | io-console (~> 0.5)
202 | responders (3.1.1)
203 | actionpack (>= 5.2)
204 | railties (>= 5.2)
205 | rexml (3.4.1)
206 | ruby-progressbar (1.13.0)
207 | ruby2_keywords (0.0.5)
208 | securerandom (0.4.1)
209 | simplecov (0.22.0)
210 | docile (~> 1.1)
211 | simplecov-html (~> 0.11)
212 | simplecov_json_formatter (~> 0.1)
213 | simplecov-cobertura (2.1.0)
214 | rexml
215 | simplecov (~> 0.19)
216 | simplecov-html (0.13.1)
217 | simplecov_json_formatter (0.1.4)
218 | stringio (3.1.7)
219 | thor (1.3.2)
220 | timeout (0.4.3)
221 | tzinfo (2.0.6)
222 | concurrent-ruby (~> 1.0)
223 | useragent (0.16.11)
224 | warning (1.5.0)
225 | websocket-driver (0.7.7)
226 | base64
227 | websocket-extensions (>= 0.1.0)
228 | websocket-extensions (0.1.5)
229 | zeitwerk (2.6.18)
230 |
231 | PLATFORMS
232 | aarch64-linux
233 | arm64-darwin
234 | ruby
235 | x86_64-darwin
236 | x86_64-linux
237 |
238 | DEPENDENCIES
239 | inherited_resources!
240 | minitest
241 | minitest-reporters
242 | mocha
243 | rails (~> 7.2.0)
244 | rails-controller-testing
245 | simplecov
246 | simplecov-cobertura
247 | warning
248 | zeitwerk (~> 2.6.18)
249 |
250 | BUNDLED WITH
251 | 2.6.8
252 |
--------------------------------------------------------------------------------
/inherited_resources.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | lib = File.expand_path("lib", __dir__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require "inherited_resources/version"
5 |
6 | Gem::Specification.new do |s|
7 | s.name = "inherited_resources"
8 | s.version = InheritedResources::VERSION.dup
9 | s.platform = Gem::Platform::RUBY
10 | s.summary = "Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important."
11 | s.homepage = "https://github.com/activeadmin/inherited_resources"
12 | s.description = <<~MSG
13 | Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important.
14 | It makes your controllers more powerful and cleaner at the same time.
15 | MSG
16 |
17 | s.authors = ['José Valim', 'Rafael Mendonça França']
18 | s.license = "MIT"
19 |
20 | s.files = Dir["app/**/*", "lib/**/*", "README.md", "MIT-LICENSE"]
21 | s.require_paths = ["lib"]
22 |
23 | s.metadata = { "rubygems_mfa_required" => "true" }
24 |
25 | s.required_ruby_version = '>= 3.1'
26 |
27 | s.add_dependency("responders", ">= 2")
28 | s.add_dependency("actionpack", ">= 7.0")
29 | s.add_dependency("railties", ">= 7.0")
30 | s.add_dependency("has_scope", ">= 0.6")
31 | end
32 |
--------------------------------------------------------------------------------
/lib/generators/rails/USAGE:
--------------------------------------------------------------------------------
1 | Description:
2 | Stubs out a scaffolded controller and its views using InheritedResources.
3 | Pass the model name, either CamelCased or under_scored. The controller
4 | name is retrieved as a pluralized version of the model name.
5 |
6 | To create a controller within a module, specify the model name as a
7 | path like 'parent_module/controller_name'.
8 |
9 | This generates a controller class in app/controllers and invokes helper,
10 | template engine and test framework generators.
11 |
--------------------------------------------------------------------------------
/lib/generators/rails/inherited_resources_controller_generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
4 |
5 | module Rails
6 | module Generators
7 | class InheritedResourcesControllerGenerator < ScaffoldControllerGenerator
8 | def self.source_root
9 | @source_root ||= File.expand_path("templates", File.dirname(__FILE__))
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/generators/rails/templates/controller.rb.tt:
--------------------------------------------------------------------------------
1 | class <%= controller_class_name %>Controller < InheritedResources::Base
2 | <% if options[:singleton] -%>
3 | defaults :singleton => true
4 | <% end -%>
5 |
6 | private
7 |
8 | def <%= singular_name %>_params
9 | params.require(:<%= singular_name %>).permit(<%= attributes_names.map{ |a_name| ":#{a_name}" }.join(", ") %>)
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/lib/inherited_resources.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This is here because responders don't require it.
4 | require 'rails/engine'
5 | require 'responders'
6 |
7 | require_relative 'inherited_resources/engine'
8 | require_relative 'inherited_resources/blank_slate'
9 | require_relative 'inherited_resources/responder'
10 |
11 | module InheritedResources
12 | ACTIONS = [ :index, :show, :new, :edit, :create, :update, :destroy ] unless self.const_defined?(:ACTIONS)
13 |
14 | autoload :Actions, 'inherited_resources/actions'
15 | autoload :BaseHelpers, 'inherited_resources/base_helpers'
16 | autoload :ShallowHelpers, 'inherited_resources/shallow_helpers'
17 | autoload :BelongsToHelpers, 'inherited_resources/belongs_to_helpers'
18 | autoload :ClassMethods, 'inherited_resources/class_methods'
19 | autoload :DSL, 'inherited_resources/dsl'
20 | autoload :PolymorphicHelpers, 'inherited_resources/polymorphic_helpers'
21 | autoload :SingletonHelpers, 'inherited_resources/singleton_helpers'
22 | autoload :UrlHelpers, 'inherited_resources/url_helpers'
23 | autoload :VERSION, 'inherited_resources/version'
24 |
25 | # Change the flash keys used by FlashResponder.
26 | def self.flash_keys=(array)
27 | Responders::FlashResponder.flash_keys = array
28 | end
29 |
30 | # Inherit from a different controller. This only has an effect if changed
31 | # before InheritedResources::Base is loaded, e.g. in a rails initializer.
32 | mattr_accessor(:parent_controller) { '::ApplicationController' }
33 | end
34 |
35 | ActiveSupport.on_load(:action_controller_base) do
36 | # If you cannot inherit from InheritedResources::Base you can call
37 | # inherit_resources in your controller to have all the required modules and
38 | # functionality included.
39 | def self.inherit_resources
40 | InheritedResources::Base.inherit_resources(self)
41 | initialize_resources_class_accessors!
42 | create_resources_url_helpers!
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/inherited_resources/actions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | # Holds all default actions for InheritedResources.
5 | module Actions
6 |
7 | # GET /resources
8 | def index(options={}, &block)
9 | respond_with(*with_chain(collection), options, &block)
10 | end
11 | alias :index! :index
12 |
13 | # GET /resources/1
14 | def show(options={}, &block)
15 | respond_with(*with_chain(resource), options, &block)
16 | end
17 | alias :show! :show
18 |
19 | # GET /resources/new
20 | def new(options={}, &block)
21 | respond_with(*with_chain(build_resource), options, &block)
22 | end
23 | alias :new! :new
24 |
25 | # GET /resources/1/edit
26 | def edit(options={}, &block)
27 | respond_with(*with_chain(resource), options, &block)
28 | end
29 | alias :edit! :edit
30 |
31 | # POST /resources
32 | def create(options={}, &block)
33 | object = build_resource
34 |
35 | if create_resource(object)
36 | options[:location] ||= smart_resource_url
37 | end
38 |
39 | respond_with_dual_blocks(object, options, &block)
40 | end
41 | alias :create! :create
42 |
43 | # PUT /resources/1
44 | def update(options={}, &block)
45 | object = resource
46 |
47 | if update_resource(object, resource_params)
48 | options[:location] ||= smart_resource_url
49 | end
50 |
51 | respond_with_dual_blocks(object, options, &block)
52 | end
53 | alias :update! :update
54 |
55 | # DELETE /resources/1
56 | def destroy(options={}, &block)
57 | object = resource
58 | options[:location] ||= smart_collection_url
59 |
60 | destroy_resource(object)
61 | respond_with_dual_blocks(object, options, &block)
62 | end
63 | alias :destroy! :destroy
64 |
65 | # Make aliases protected
66 | protected :index!, :show!, :new!, :create!, :edit!, :update!, :destroy!
67 | end
68 | end
69 |
--------------------------------------------------------------------------------
/lib/inherited_resources/belongs_to_helpers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 |
5 | # = belongs_to
6 | #
7 | # Let's suppose that we have some tasks that belongs to projects. To specify
8 | # this association in your controllers, just do:
9 | #
10 | # class TasksController < InheritedResources::Base
11 | # belongs_to :project
12 | # end
13 | #
14 | # belongs_to accepts several options to be able to configure the association.
15 | # For example, if you want urls like /projects/:project_title/tasks, you
16 | # can customize how InheritedResources find your projects:
17 | #
18 | # class TasksController < InheritedResources::Base
19 | # belongs_to :project, :finder => :find_by_title!, :param => :project_title
20 | # end
21 | #
22 | # It also accepts :route_name, :parent_class and :instance_name as options.
23 | # Check the lib/inherited_resources/class_methods.rb for more.
24 | #
25 | # = nested_belongs_to
26 | #
27 | # Now, our Tasks get some Comments and you need to nest even deeper. Good
28 | # practices says that you should never nest more than two resources, but sometimes
29 | # you have to for security reasons. So this is an example of how you can do it:
30 | #
31 | # class CommentsController < InheritedResources::Base
32 | # nested_belongs_to :project, :task
33 | # end
34 | #
35 | # If you need to configure any of these belongs to, you can nested them using blocks:
36 | #
37 | # class CommentsController < InheritedResources::Base
38 | # belongs_to :project, :finder => :find_by_title!, :param => :project_title do
39 | # belongs_to :task
40 | # end
41 | # end
42 | #
43 | # Warning: calling several belongs_to is the same as nesting them:
44 | #
45 | # class CommentsController < InheritedResources::Base
46 | # belongs_to :project
47 | # belongs_to :task
48 | # end
49 | #
50 | # In other words, the code above is the same as calling nested_belongs_to.
51 | #
52 | module BelongsToHelpers
53 |
54 | protected
55 |
56 | # Parent is always true when belongs_to is called.
57 | #
58 | def parent?
59 | true
60 | end
61 |
62 | def parent
63 | @parent ||= association_chain[-1]
64 | end
65 |
66 | def parent_type
67 | parent.class.name.underscore.to_sym
68 | end
69 |
70 | private
71 |
72 | # Evaluate the parent given. This is used to nest parents in the
73 | # association chain.
74 | #
75 | def evaluate_parent(parent_symbol, parent_config, chain = nil) #:nodoc:
76 | get_parent_ivar(parent_config[:instance_name]) ||
77 | set_parent_instance(parent_config, chain)
78 | end
79 |
80 | def get_parent_ivar(instance_name) #:nodoc:
81 | instance_variable_defined?(:"@#{instance_name}") &&
82 | instance_variable_get(:"@#{instance_name}")
83 | end
84 |
85 | def set_parent_instance(parent_config, chain) #:nodoc:
86 | if parent_config[:singleton]
87 | parent = if chain
88 | chain.send(parent_config[:instance_name])
89 | else
90 | nil
91 | end
92 | else
93 | parent = if chain
94 | chain.send(parent_config[:collection_name])
95 | else
96 | parent_config[:parent_class]
97 | end
98 |
99 | parent = parent.send(parent_config[:finder], params[parent_config[:param]])
100 | end
101 |
102 | instance_variable_set(:"@#{parent_config[:instance_name]}", parent)
103 | end
104 |
105 | # Maps parents_symbols to build association chain. In this case, it
106 | # simply return the parent_symbols, however on polymorphic belongs to,
107 | # it has some customization.
108 | #
109 | def symbols_for_association_chain #:nodoc:
110 | parents_symbols
111 | end
112 |
113 | end
114 | end
115 |
--------------------------------------------------------------------------------
/lib/inherited_resources/blank_slate.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | # An object from BlankSlate simply discards all messages sent to it.
5 | class BlankSlate
6 | instance_methods.each do |m|
7 | undef_method m unless /^(__|object_id)/.match?(m)
8 | end
9 |
10 | def method_missing(*args)
11 | nil
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/lib/inherited_resources/dsl.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | # Allows controllers to write actions using a class method DSL.
5 | #
6 | # class MyController < InheritedResources::Base
7 | # create! do |success, failure|
8 | # success.html { render :text => "It works!" }
9 | # end
10 | # end
11 | #
12 | module DSL
13 | def self.included(base)
14 | ACTIONS.each do |action|
15 | base.class_eval <<-WRITTER
16 | def self.#{action}!(options={}, &block)
17 | define_method :__#{action}, &block
18 | class_eval <<-ACTION
19 | def #{action}
20 | super(\#{options.inspect}, &method(:__#{action}))
21 | end
22 | ACTION
23 | end
24 | WRITTER
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/inherited_resources/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | class Railtie < ::Rails::Engine
5 | config.inherited_resources = InheritedResources
6 |
7 | if config.respond_to?(:app_generators)
8 | config.app_generators.scaffold_controller = :inherited_resources_controller
9 | else
10 | config.generators.scaffold_controller = :inherited_resources_controller
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/inherited_resources/polymorphic_helpers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 |
5 | # = polymorphic associations
6 | #
7 | # In some cases you have a resource that belongs to two different resources
8 | # but not at the same time. For example, let's suppose you have File, Message
9 | # and Task as resources and they are all commentable.
10 | #
11 | # Polymorphic associations allows you to create just one controller that will
12 | # deal with each case.
13 | #
14 | # class Comment < InheritedResources::Base
15 | # belongs_to :file, :message, :task, :polymorphic => true
16 | # end
17 | #
18 | # Your routes should be something like:
19 | #
20 | # resources :files do
21 | # resources :comments #=> /files/13/comments
22 | # end
23 | # resources :tasks do
24 | # resources :comments #=> /tasks/17/comments
25 | # end
26 | # resources :messages do
27 | # resources :comments #=> /messages/11/comments
28 | # end
29 | #
30 | # When using polymorphic associations, you get some free helpers:
31 | #
32 | # parent? #=> true
33 | # parent_type #=> :task
34 | # parent_class #=> Task
35 | # parent #=> @task
36 | #
37 | # This polymorphic controllers thing is a great idea by James Golick and he
38 | # built it in resource_controller. Here is just a re-implementation.
39 | #
40 | # = optional polymorphic associations
41 | #
42 | # Let's take another break from ProjectsController. Let's suppose we are
43 | # building a store, which sell products.
44 | #
45 | # On the website, we can show all products, but also products scoped to
46 | # categories, brands, users. In this case case, the association is optional, and
47 | # we deal with it in the following way:
48 | #
49 | # class ProductsController < InheritedResources::Base
50 | # belongs_to :category, :brand, :user, :polymorphic => true, :optional => true
51 | # end
52 | #
53 | # This will handle all those urls properly:
54 | #
55 | # /products/1
56 | # /categories/2/products/5
57 | # /brands/10/products/3
58 | # /user/13/products/11
59 | #
60 | # = nested polymorphic associations
61 | #
62 | # You can have polymorphic associations with nested resources. Let's suppose
63 | # that our File, Task and Message resources in the previous example belongs to
64 | # a project.
65 | #
66 | # This way we can have:
67 | #
68 | # class CommentsController < InheritedResources::Base
69 | # belongs_to :project {
70 | # belongs_to :file, :message, :task, :polymorphic => true
71 | # }
72 | # end
73 | #
74 | # Or:
75 | #
76 | # class CommentsController < InheritedResources::Base
77 | # nested_belongs_to :project
78 | # nested_belongs_to :file, :message, :task, :polymorphic => true
79 | # end
80 | #
81 | # Choose the syntax that makes more sense to you. :)
82 | #
83 | # Finally your routes should be something like:
84 | #
85 | # resources :projects do
86 | # resources :files do
87 | # resources :comments #=> /projects/1/files/13/comments
88 | # end
89 | # resources :tasks do
90 | # resources :comments #=> /projects/1/tasks/17/comments
91 | # end
92 | # resources :messages do
93 | # resources :comments #=> /projects/1/messages/11/comments
94 | # end
95 | # end
96 | #
97 | # The helpers work in the same way as above.
98 | #
99 | module PolymorphicHelpers
100 |
101 | protected
102 |
103 | # Returns the parent type. A Comments class can have :task, :file, :note
104 | # as parent types.
105 | #
106 | def parent_type
107 | unless instance_variable_defined?(:@parent_type)
108 | symbols_for_association_chain
109 | end
110 |
111 | if instance_variable_defined?(:@parent_type)
112 | @parent_type
113 | end
114 | end
115 |
116 | def parent_class
117 | parent.class if parent_type
118 | end
119 |
120 | # Returns the parent object. They are also available with the instance
121 | # variable name: @task, @file, @note...
122 | #
123 | def parent
124 | if parent_type
125 | p = instance_variable_defined?(:"@#{parent_type}") && instance_variable_get(:"@#{parent_type}")
126 | p || instance_variable_set(:"@#{parent_type}", association_chain[-1])
127 | end
128 | end
129 |
130 | # If the polymorphic association is optional, we might not have a parent.
131 | #
132 | def parent?
133 | if resources_configuration[:polymorphic][:optional]
134 | parents_symbols.size > 1 || !parent_type.nil?
135 | else
136 | true
137 | end
138 | end
139 |
140 | private
141 |
142 | # Maps parents_symbols to build association chain.
143 | #
144 | # If the parents_symbols find :polymorphic, it goes through the
145 | # params keys to see which polymorphic parent matches the given params.
146 | #
147 | # When optional is given, it does not raise errors if the polymorphic
148 | # params are missing.
149 | #
150 | def symbols_for_association_chain #:nodoc:
151 | polymorphic_config = resources_configuration[:polymorphic]
152 | parents_symbols.map do |symbol|
153 | if symbol == :polymorphic
154 | params_keys = params.keys
155 |
156 | keys = polymorphic_config[:symbols].select do |poly|
157 | params_keys.include?(resources_configuration[poly][:param].to_s)
158 | end
159 |
160 | if keys.empty?
161 | raise ScriptError, "Could not find param for polymorphic association. The request " <<
162 | "parameters are #{params.keys.inspect} and the polymorphic " <<
163 | "associations are #{polymorphic_config[:symbols].inspect}." unless polymorphic_config[:optional]
164 |
165 | nil
166 | else
167 | @parent_type = keys[-1].to_sym
168 | @parent_types = keys.map(&:to_sym)
169 | end
170 | else
171 | symbol
172 | end
173 | end.flatten.compact
174 | end
175 |
176 | end
177 | end
178 |
--------------------------------------------------------------------------------
/lib/inherited_resources/responder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | class Responder < ActionController::Responder
5 | include Responders::FlashResponder
6 |
7 | self.error_status = :unprocessable_entity
8 | self.redirect_status = :see_other
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/lib/inherited_resources/shallow_helpers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | # Shallow provides a functionality that goes on pair with Rails' shallow.
5 | # It is very similar to "optional" but it actually finds all the parents
6 | # resources instead of leaving them blank. Consider the following example:
7 | #
8 | # belongs_to :post, :shallow => true do
9 | # belongs_to :comment
10 | # end
11 | #
12 | # When accessed as /comments/1, Inherited Resources will automatically get
13 | # the post resource so both objects are actually accessible through the views.
14 | #
15 | # However, when using optional, Inherited Resources wouldn't actually bother
16 | # with finding the parent object.
17 | module ShallowHelpers
18 | private
19 |
20 | def symbols_for_association_chain #:nodoc:
21 | parent_symbols = parents_symbols.dup
22 | instance = nil
23 |
24 | if id = params[:id]
25 | finder_method = resources_configuration[:self][:finder] || :find
26 | instance = self.resource_class.send(finder_method, id)
27 | elsif parents_symbols.size > 1
28 | config = resources_configuration[parent_symbols.pop]
29 | finder_method = config[:finder] || :find
30 | instance = config[:parent_class].send(finder_method, params[config[:param]])
31 | end
32 |
33 | load_parents(instance, parent_symbols) if instance
34 | parents_symbols
35 | end
36 |
37 | def load_parents(instance, parent_symbols)
38 | parent_symbols.reverse_each do |parent|
39 | instance = instance.send(parent)
40 | config = resources_configuration[parent]
41 | params[config[:param]] = instance.to_param
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/lib/inherited_resources/singleton_helpers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 |
5 | # = singleton
6 | #
7 | # Singletons are usually used in associations which are related through has_one
8 | # and belongs_to. You declare those associations like this:
9 | #
10 | # class ManagersController < InheritedResources::Base
11 | # belongs_to :project, :singleton => true
12 | # end
13 | #
14 | # But in some cases, like an AccountsController, you have a singleton object
15 | # that is not necessarily associated with another:
16 | #
17 | # class AccountsController < InheritedResources::Base
18 | # defaults :singleton => true
19 | # end
20 | #
21 | # Besides that, you should overwrite the methods :resource and :build_resource
22 | # to make it work properly:
23 | #
24 | # class AccountsController < InheritedResources::Base
25 | # defaults :singleton => true
26 | #
27 | # protected
28 | # def resource
29 | # @current_user.account
30 | # end
31 | #
32 | # def build_resource(attributes = {})
33 | # Account.new(attributes)
34 | # end
35 | # end
36 | #
37 | # When you have a singleton controller, the action index is removed.
38 | #
39 | module SingletonHelpers
40 |
41 | protected
42 |
43 | # Singleton methods does not deal with collections.
44 | #
45 | def collection; end
46 |
47 | # Overwrites how singleton deals with resource.
48 | #
49 | # If you are going to overwrite it, you should notice that the
50 | # end_of_association_chain here is not the same as in default belongs_to.
51 | #
52 | # class TasksController < InheritedResources::Base
53 | # belongs_to :project
54 | # end
55 | #
56 | # In this case, the association chain would be:
57 | #
58 | # Project.find(params[:project_id]).tasks
59 | #
60 | # So you would just have to call find(:all) at the end of association
61 | # chain. And this is what happened.
62 | #
63 | # In singleton controllers:
64 | #
65 | # class ManagersController < InheritedResources::Base
66 | # belongs_to :project, :singleton => true
67 | # end
68 | #
69 | # The association chain will be:
70 | #
71 | # Project.find(params[:project_id])
72 | #
73 | # So we have to call manager on it, not find.
74 | #
75 | def resource
76 | get_resource_ivar || set_resource_ivar(end_of_association_chain.send(resource_instance_name))
77 | end
78 |
79 | private
80 |
81 | # Returns the appropriated method to build the resource.
82 | #
83 | def method_for_association_build #:nodoc:
84 | :"build_#{resource_instance_name}"
85 | end
86 |
87 | # Sets the method_for_association_chain to nil. See resource
88 | # above for more information.
89 | #
90 | def method_for_association_chain #:nodoc:
91 | nil
92 | end
93 |
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/lib/inherited_resources/url_helpers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module InheritedResources
4 | # = URLHelpers
5 | #
6 | # When you use InheritedResources it creates some UrlHelpers for you.
7 | # And they handle everything for you.
8 | #
9 | # # /posts/1/comments
10 | # resource_url # => /posts/1/comments/#{@comment.to_param}
11 | # resource_url(comment) # => /posts/1/comments/#{comment.to_param}
12 | # new_resource_url # => /posts/1/comments/new
13 | # edit_resource_url # => /posts/1/comments/#{@comment.to_param}/edit
14 | # collection_url # => /posts/1/comments
15 | # parent_url # => /posts/1
16 | #
17 | # # /projects/1/tasks
18 | # resource_url # => /projects/1/tasks/#{@task.to_param}
19 | # resource_url(task) # => /projects/1/tasks/#{task.to_param}
20 | # new_resource_url # => /projects/1/tasks/new
21 | # edit_resource_url # => /projects/1/tasks/#{@task.to_param}/edit
22 | # collection_url # => /projects/1/tasks
23 | # parent_url # => /projects/1
24 | #
25 | # # /users
26 | # resource_url # => /users/#{@user.to_param}
27 | # resource_url(user) # => /users/#{user.to_param}
28 | # new_resource_url # => /users/new
29 | # edit_resource_url # => /users/#{@user.to_param}/edit
30 | # collection_url # => /users
31 | # parent_url # => /
32 | #
33 | # The nice thing is that those urls are not guessed during runtime. They are
34 | # all created when you inherit.
35 | #
36 | module UrlHelpers
37 | protected
38 |
39 | # This method hard code url helpers in the class.
40 | #
41 | # We are doing this because is cheaper than guessing them when our action
42 | # is being processed (and even more cheaper when we are using nested
43 | # resources).
44 | #
45 | # When we are using polymorphic associations, those helpers rely on
46 | # polymorphic_url Rails helper.
47 | #
48 | def create_resources_url_helpers!
49 | resource_segments, resource_ivars = [], []
50 | resource_config = self.resources_configuration[:self]
51 |
52 | singleton = resource_config[:singleton]
53 | uncountable = !singleton && resource_config[:route_collection_name] == resource_config[:route_instance_name]
54 | polymorphic = self.parents_symbols.include?(:polymorphic)
55 |
56 | # Add route_prefix if any.
57 | unless resource_config[:route_prefix].blank?
58 | if polymorphic
59 | resource_ivars << resource_config[:route_prefix]
60 | else
61 | resource_segments << resource_config[:route_prefix]
62 | end
63 | end
64 |
65 | # Deal with belongs_to associations and polymorphic associations.
66 | # Remember that we don't have to build the segments in polymorphic cases,
67 | # because the url will be polymorphic_url.
68 | #
69 | self.parents_symbols.each do |symbol|
70 | if symbol == :polymorphic
71 | resource_ivars << :parent
72 | else
73 | config = self.resources_configuration[symbol]
74 | if config[:singleton] && polymorphic
75 | resource_ivars << config[:instance_name]
76 | else
77 | resource_segments << config[:route_name]
78 | end
79 | if !config[:singleton]
80 | resource_ivars << :"@#{config[:instance_name]}"
81 | end
82 | end
83 | end
84 |
85 | collection_ivars = resource_ivars.dup
86 | collection_segments = resource_segments.dup
87 |
88 | # Generate parent url before we add resource instances.
89 | unless parents_symbols.empty?
90 | generate_url_and_path_helpers nil, :parent, resource_segments, resource_ivars
91 | generate_url_and_path_helpers :edit, :parent, resource_segments, resource_ivars
92 | end
93 |
94 | # In singleton cases, we do not send the current element instance variable
95 | # because the id is not in the URL. For example, we should call:
96 | #
97 | # project_manager_url(@project)
98 | #
99 | # Instead of:
100 | #
101 | # project_manager_url(@project, @manager)
102 | #
103 | # Another exception in singleton cases is that collection url does not
104 | # exist. In such cases, we create the parent collection url. So in the
105 | # manager case above, the collection url will be:
106 | #
107 | # project_url(@project)
108 | #
109 | # If the singleton does not have a parent, it will default to root_url.
110 | #
111 | collection_segments << resource_config[:route_collection_name] unless singleton
112 | resource_segments << resource_config[:route_instance_name]
113 | resource_ivars << :"@#{resource_config[:instance_name]}" unless singleton
114 |
115 | # Finally, polymorphic cases we have to give hints to the polymorphic url
116 | # builder. This works by attaching new ivars as symbols or records.
117 | #
118 | if polymorphic && singleton
119 | resource_ivars << resource_config[:instance_name]
120 | new_ivars = resource_ivars
121 | end
122 |
123 | # If route is uncountable then add "_index" suffix to collection index route name
124 | if uncountable
125 | collection_segments << :"#{collection_segments.pop}_index"
126 | end
127 |
128 | generate_url_and_path_helpers nil, :collection, collection_segments, collection_ivars
129 | generate_url_and_path_helpers :new, :resource, resource_segments, new_ivars || collection_ivars
130 | generate_url_and_path_helpers nil, :resource, resource_segments, resource_ivars
131 | generate_url_and_path_helpers :edit, :resource, resource_segments, resource_ivars
132 |
133 | if resource_config[:custom_actions]
134 | [*resource_config[:custom_actions][:resource]].each do | method |
135 | generate_url_and_path_helpers method, :resource, resource_segments, resource_ivars
136 | end
137 | [*resource_config[:custom_actions][:collection]].each do | method |
138 | generate_url_and_path_helpers method, :resources, collection_segments, collection_ivars
139 | end
140 | end
141 | end
142 |
143 | def handle_shallow_resource(prefix, name, segments, ivars) #:nodoc:
144 | return segments, ivars unless self.resources_configuration[:self][:shallow]
145 | case name
146 | when :collection, :resources
147 | segments = segments[-2..-1]
148 | ivars = [ivars.last]
149 | when :resource
150 | if prefix == :new
151 | segments = segments[-2..-1]
152 | ivars = [ivars.last]
153 | else
154 | segments = [segments.last]
155 | ivars = [ivars.last]
156 | end
157 | when :parent
158 | segments = [segments.last]
159 | ivars = [ivars.last]
160 | end
161 |
162 | segments ||= []
163 |
164 | unless self.resources_configuration[:self][:route_prefix].blank?
165 | segments.unshift self.resources_configuration[:self][:route_prefix]
166 | end
167 |
168 | return segments, ivars
169 | end
170 |
171 | def generate_url_and_path_helpers(prefix, name, resource_segments, resource_ivars) #:nodoc:
172 | resource_segments, resource_ivars = handle_shallow_resource(prefix, name, resource_segments, resource_ivars)
173 |
174 | ivars = resource_ivars.dup
175 | singleton = self.resources_configuration[:self][:singleton]
176 | polymorphic = self.parents_symbols.include?(:polymorphic)
177 |
178 | # In collection in polymorphic cases, allow an argument to be given as a
179 | # replacemente for the parent.
180 | #
181 | parent_index = ivars.index(:parent) if polymorphic
182 |
183 | segments = if polymorphic
184 | :polymorphic
185 | elsif resource_segments.empty?
186 | 'root'
187 | else
188 | resource_segments.join('_')
189 | end
190 |
191 | define_params_helper(prefix, name, singleton, polymorphic, parent_index, ivars)
192 | define_helper_method(prefix, name, :path, segments)
193 | define_helper_method(prefix, name, :url, segments)
194 | end
195 |
196 | def define_params_helper(prefix, name, singleton, polymorphic, parent_index, ivars)
197 | params_method_name = ['', prefix, name, :params].compact.join('_')
198 |
199 | undef_method params_method_name if method_defined? params_method_name
200 |
201 | define_method params_method_name do |*given_args|
202 | given_args = given_args.collect { |arg| arg.respond_to?(:permitted?) ? arg.to_h : arg }
203 | given_options = given_args.extract_options!
204 |
205 | args = ivars.map do |ivar|
206 | ivar.is_a?(Symbol) && ivar.to_s.start_with?('@') ? instance_variable_get(ivar) : ivar
207 | end
208 | args[parent_index] = parent if parent_index
209 |
210 | if !(singleton && name != :parent) && args.present? && name != :collection && prefix != :new
211 | resource = args.pop
212 | args.push(given_args.first || resource)
213 | end
214 |
215 | if polymorphic
216 | if name == :collection
217 | args[parent_index] = given_args.present? ? given_args.first : parent
218 | end
219 | if (name == :collection || name == :resource && prefix == :new) && !singleton
220 | args << (@_resource_class_new ||= resource_class.new)
221 | end
222 | args.compact! if self.resources_configuration[:polymorphic][:optional]
223 | args = [args]
224 | end
225 | args << given_options
226 | end
227 | protected params_method_name
228 | end
229 |
230 | def define_helper_method(prefix, name, suffix, segments)
231 | method_name = [prefix, name, suffix].compact.join('_')
232 | params_method_name = ['', prefix, name, :params].compact.join('_')
233 | segments_method = [prefix, segments, suffix].compact.join('_')
234 |
235 | undef_method method_name if method_defined? method_name
236 |
237 | define_method method_name do |*given_args|
238 | given_args = send params_method_name, *given_args
239 | send segments_method, *given_args
240 | end
241 | protected method_name
242 | end
243 |
244 | end
245 | end
246 |
--------------------------------------------------------------------------------
/lib/inherited_resources/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module InheritedResources
3 | VERSION = '2.1.0'.freeze
4 | end
5 |
--------------------------------------------------------------------------------
/test/aliases_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Student
5 | extend ActiveModel::Naming
6 | end
7 |
8 | class ApplicationController < ActionController::Base
9 | include InheritedResources::DSL
10 | end
11 |
12 | class StudentsController < ApplicationController
13 | inherit_resources
14 | respond_to :html, :xml
15 |
16 | def edit
17 | edit! do |format|
18 | format.xml { render plain: 'Render XML' }
19 | end
20 | end
21 |
22 | def new
23 | @something = 'magical'
24 | new!
25 | end
26 |
27 | create!(location: "http://test.host/") do |success, failure|
28 | success.html { render plain: "I won't redirect!" }
29 | failure.xml { render plain: "I shouldn't be rendered" }
30 | end
31 |
32 | update! do |success, failure|
33 | success.html { redirect_to(resource_url) }
34 | failure.html { render plain: "I won't render!" }
35 | end
36 |
37 | destroy! do |format|
38 | format.html { render plain: "Destroyed!" }
39 | end
40 | end
41 |
42 | class AliasesTest < ActionController::TestCase
43 | tests StudentsController
44 |
45 | def setup
46 | draw_routes do
47 | resources :students
48 | end
49 | end
50 |
51 | def teardown
52 | clear_routes
53 | end
54 |
55 | def test_assignments_before_calling_alias
56 | Student.stubs(:new).returns(mock_student)
57 | get :new
58 |
59 | assert_response :success
60 | assert_equal 'magical', assigns(:something)
61 | end
62 |
63 | def test_controller_should_render_new
64 | Student.stubs(:new).returns(mock_student)
65 | get :new
66 |
67 | assert_response :success
68 | assert_equal 'New HTML', @response.body.strip
69 | end
70 |
71 | def test_expose_the_requested_user_on_edit
72 | Student.expects(:find).with('42').returns(mock_student)
73 | get :edit, params: { id: '42' }
74 |
75 | assert_equal mock_student, assigns(:student)
76 | assert_response :success
77 | end
78 |
79 | def test_controller_should_render_edit
80 | Student.stubs(:find).returns(mock_student)
81 | get :edit, params: { id: '42' }
82 |
83 | assert_response :success
84 | assert_equal 'Edit HTML', @response.body.strip
85 | end
86 |
87 | def test_render_xml_when_it_is_given_as_a_block
88 | @request.accept = 'application/xml'
89 | Student.stubs(:find).returns(mock_student)
90 | get :edit, params: { id: '42' }
91 |
92 | assert_response :success
93 | assert_equal 'Render XML', @response.body
94 | end
95 |
96 | def test_is_not_redirected_on_create_with_success_if_success_block_is_given
97 | Student.stubs(:new).returns(mock_student(save: true))
98 | @controller.stubs(:resource_url).returns('http://test.host/')
99 | post :create
100 |
101 | assert_response :success
102 | assert_equal "I won't redirect!", @response.body
103 | end
104 |
105 | def test_dumb_responder_quietly_receives_everything_on_failure
106 | @request.accept = 'text/html'
107 | Student.stubs(:new).returns(mock_student(save: false, errors: {some: :error}))
108 | @controller.stubs(:resource_url).returns('http://test.host/')
109 | post :create
110 |
111 | assert_response :unprocessable_entity
112 | assert_equal "New HTML", @response.body.strip
113 | end
114 |
115 | def test_html_is_the_default_when_only_xml_is_overwritten
116 | @request.accept = '*/*'
117 | Student.stubs(:new).returns(mock_student(save: false, errors: {some: :error}))
118 | @controller.stubs(:resource_url).returns('http://test.host/')
119 | post :create
120 |
121 | assert_response :unprocessable_entity
122 | assert_equal "New HTML", @response.body.strip
123 | end
124 |
125 | def test_wont_render_edit_template_on_update_with_failure_if_failure_block_is_given
126 | Student.stubs(:find).returns(mock_student(update: false, errors: { fail: true }))
127 | put :update, params: { id: '42' }
128 |
129 | assert_response :success
130 | assert_equal "I won't render!", @response.body
131 | end
132 |
133 | def test_dumb_responder_quietly_receives_everything_on_success
134 | Student.stubs(:find).returns(mock_student(update: true))
135 | @controller.stubs(:resource_url).returns('http://test.host/')
136 | put :update, params: { id: '42', student: {these: 'params'} }
137 |
138 | assert_equal mock_student, assigns(:student)
139 | end
140 |
141 | def test_block_is_called_when_student_is_destroyed
142 | Student.stubs(:find).returns(mock_student(destroy: true))
143 | delete :destroy, params: { id: '42' }
144 |
145 | assert_response :success
146 | assert_equal "Destroyed!", @response.body
147 | end
148 |
149 | def test_options_are_used_in_respond_with
150 | @request.accept = "application/xml"
151 | mock_student = mock_student(save: true, to_xml: "XML")
152 | Student.stubs(:new).returns(mock_student)
153 |
154 | post :create
155 |
156 | assert_equal "http://test.host/", @response.location
157 | end
158 |
159 | protected
160 |
161 | def mock_student(expectations={})
162 | @mock_student ||= begin
163 | student = mock(expectations.except(:errors))
164 | student.stubs(:class).returns(Student)
165 | student.stubs(:errors).returns(expectations.fetch(:errors, {}))
166 | student
167 | end
168 | end
169 | end
170 |
--------------------------------------------------------------------------------
/test/association_chain_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Pet
5 | extend ActiveModel::Naming
6 | end
7 |
8 | class Puppet
9 | extend ActiveModel::Naming
10 | end
11 |
12 | class PetsController < InheritedResources::Base
13 | attr_accessor :current_user
14 |
15 | def edit
16 | @pet = 'new pet'
17 | edit!
18 | end
19 |
20 | protected
21 |
22 | def collection
23 | @pets ||= end_of_association_chain.all
24 | end
25 |
26 | def begin_of_association_chain
27 | @current_user
28 | end
29 | end
30 |
31 | class BeginOfAssociationChainTest < ActionController::TestCase
32 | tests PetsController
33 |
34 | def setup
35 | draw_routes do
36 | resources :pets
37 | end
38 |
39 | @controller.current_user = mock()
40 | end
41 |
42 | def teardown
43 | clear_routes
44 | end
45 |
46 | def test_begin_of_association_chain_is_called_on_index
47 | @controller.current_user.expects(:pets).returns(Pet)
48 | Pet.expects(:all).returns(mock_pet)
49 | get :index
50 |
51 | assert_response :success
52 | assert_equal 'Index HTML', @response.body.strip
53 | end
54 |
55 | def test_begin_of_association_chain_is_called_on_new
56 | @controller.current_user.expects(:pets).returns(Pet)
57 | Pet.expects(:build).returns(mock_pet)
58 | get :new
59 |
60 | assert_response :success
61 | assert_equal 'New HTML', @response.body.strip
62 | end
63 |
64 | def test_begin_of_association_chain_is_called_on_show
65 | @controller.current_user.expects(:pets).returns(Pet)
66 | Pet.expects(:find).with('47').returns(mock_pet)
67 | get :show, params: { id: '47' }
68 |
69 | assert_response :success
70 | assert_equal 'Show HTML', @response.body.strip
71 | end
72 |
73 | def test_instance_variable_should_not_be_set_if_already_defined
74 | @controller.current_user.expects(:pets).never
75 | Pet.expects(:find).never
76 | get :edit, params: { id: '47' }
77 |
78 | assert_response :success
79 | assert_equal 'new pet', assigns(:pet)
80 | end
81 |
82 | def test_model_is_not_initialized_with_nil
83 | @controller.current_user.expects(:pets).returns(Pet)
84 | Pet.expects(:build).with({}).returns(mock_pet)
85 | get :new
86 |
87 | assert_equal mock_pet, assigns(:pet)
88 | end
89 |
90 | def test_begin_of_association_chain_is_included_in_chain
91 | @controller.current_user.expects(:pets).returns(Pet)
92 | Pet.expects(:build).with({}).returns(mock_pet)
93 | get :new
94 |
95 | assert_equal [@controller.current_user], @controller.send(:association_chain)
96 | end
97 |
98 | protected
99 |
100 | def mock_pet(stubs={})
101 | @mock_pet ||= mock(stubs)
102 | end
103 | end
104 |
105 | class PuppetsController < InheritedResources::Base
106 | optional_belongs_to :pet
107 | end
108 |
109 | class AssociationChainTest < ActionController::TestCase
110 | tests PuppetsController
111 |
112 | def setup
113 | draw_routes do
114 | resources :puppets
115 | end
116 |
117 | @controller.stubs(:collection_url).returns('/')
118 | end
119 |
120 | def teardown
121 | clear_routes
122 | end
123 |
124 | def test_parent_is_added_to_association_chain
125 | Pet.expects(:find).with('37').returns(mock_pet)
126 | mock_pet.expects(:puppets).returns(Puppet)
127 | Puppet.expects(:find).with('42').returns(mock_puppet)
128 | mock_puppet.expects(:destroy)
129 | delete :destroy, params: { id: '42', pet_id: '37' }
130 |
131 | assert_equal [mock_pet], @controller.send(:association_chain)
132 | end
133 |
134 | def test_parent_is_added_to_association_chain_if_not_available
135 | Puppet.expects(:find).with('42').returns(mock_puppet)
136 | mock_puppet.expects(:destroy)
137 | delete :destroy, params: { id: '42' }
138 |
139 | assert_empty @controller.send(:association_chain)
140 | end
141 |
142 | protected
143 |
144 | def mock_pet(stubs={})
145 | @mock_pet ||= mock(stubs)
146 | end
147 |
148 | def mock_puppet(stubs={})
149 | @mock_puppet ||= mock(stubs)
150 | end
151 | end
152 |
--------------------------------------------------------------------------------
/test/autoload/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module MyTestNamespace
3 | class Engine; end
4 | end
5 |
--------------------------------------------------------------------------------
/test/base_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class User
5 | extend ActiveModel::Naming
6 | end
7 |
8 | class AccountsController < InheritedResources::Base
9 | end
10 |
11 | class UsersController < AccountsController
12 | respond_to :html, :xml
13 | respond_to :js, only: [:create, :update, :destroy]
14 | attr_reader :scopes_applied
15 |
16 | def self.name
17 | "UsersController"
18 | end
19 |
20 | protected
21 |
22 | def apply_scopes(object)
23 | @scopes_applied = true
24 | object
25 | end
26 | end
27 |
28 | module UserTestHelper
29 | def setup
30 | draw_routes do
31 | resources :users
32 | end
33 |
34 | @controller_class = Class.new(UsersController)
35 | @controller = @controller_class.new
36 | @controller.request = @request = new_request
37 | @controller.response = @response = new_response
38 | @controller.stubs(:user_url).returns("/")
39 | end
40 |
41 | def teardown
42 | clear_routes
43 | end
44 |
45 | protected
46 |
47 | def new_request
48 | ActionController::TestRequest.create(UsersController)
49 | end
50 |
51 | def new_response
52 | ActionDispatch::TestResponse.create
53 | end
54 |
55 | def mock_user(expectations={})
56 | @mock_user ||= begin
57 | user = mock(expectations.except(:errors))
58 | user.stubs(:class).returns(User)
59 | user.stubs(:errors).returns(expectations.fetch(:errors, {}))
60 | user.singleton_class.class_eval do
61 | def method_missing(symbol, *arguments, &block)
62 | raise NoMethodError.new('this is expected by Array#flatten') if symbol == :to_ary
63 | super
64 | end
65 | end
66 | user
67 | end
68 | end
69 |
70 | def build_parameters(hash)
71 | ActionController::Parameters.new(hash)
72 | end
73 | end
74 |
75 | class IndexActionBaseTest < ActionController::TestCase
76 | include UserTestHelper
77 |
78 | def test_expose_all_users_as_instance_variable
79 | User.expects(:scoped).returns([mock_user])
80 | get :index
81 |
82 | assert_equal [mock_user], assigns(:users)
83 | end
84 |
85 | def test_apply_scopes_if_method_is_available
86 | User.expects(:scoped).returns([mock_user])
87 | get :index
88 |
89 | assert @controller.scopes_applied
90 | end
91 |
92 | def test_controller_should_render_index
93 | User.stubs(:scoped).returns([mock_user])
94 | get :index
95 |
96 | assert_response :success
97 | assert_equal 'Index HTML', @response.body.strip
98 | end
99 |
100 | def test_render_all_users_as_xml_when_mime_type_is_xml
101 | @request.accept = 'application/xml'
102 | User.expects(:scoped).returns(collection = [mock_user])
103 | collection.expects(:to_xml).returns('Generated XML')
104 | get :index
105 |
106 | assert_response :success
107 | assert_equal 'Generated XML', @response.body
108 | end
109 |
110 | def test_scoped_is_called_only_when_available
111 | User.stubs(:all).returns([mock_user])
112 | get :index
113 |
114 | assert_instance_of Array, assigns(:users)
115 | end
116 | end
117 |
118 | class ShowActionBaseTest < ActionController::TestCase
119 | include UserTestHelper
120 |
121 | def test_expose_the_requested_user
122 | User.expects(:find).with('42').returns(mock_user)
123 | get :show, params: { id: '42' }
124 |
125 | assert_equal mock_user, assigns(:user)
126 | end
127 |
128 | def test_controller_should_render_show
129 | User.stubs(:find).returns(mock_user)
130 | get :show, params: { id: '42' }
131 |
132 | assert_response :success
133 | assert_equal 'Show HTML', @response.body.strip
134 | end
135 |
136 | def test_render_exposed_user_as_xml_when_mime_type_is_xml
137 | @request.accept = 'application/xml'
138 | User.expects(:find).with('42').returns(mock_user)
139 | mock_user.expects(:to_xml).returns("Generated XML")
140 |
141 | get :show, params: { id: '42' }
142 |
143 | assert_response :success
144 | assert_equal 'Generated XML', @response.body
145 | end
146 | end
147 |
148 | class NewActionBaseTest < ActionController::TestCase
149 | include UserTestHelper
150 |
151 | def test_expose_a_new_user
152 | User.expects(:new).returns(mock_user)
153 | get :new
154 |
155 | assert_equal mock_user, assigns(:user)
156 | end
157 |
158 | def test_controller_should_render_new
159 | User.stubs(:new).returns(mock_user)
160 | get :new
161 |
162 | assert_response :success
163 | assert_equal 'New HTML', @response.body.strip
164 | end
165 |
166 | def test_render_exposed_a_new_user_as_xml_when_mime_type_is_xml
167 | @request.accept = 'application/xml'
168 | User.expects(:new).returns(mock_user)
169 | mock_user.expects(:to_xml).returns("Generated XML")
170 |
171 | get :new
172 |
173 | assert_response :success
174 | assert_equal 'Generated XML', @response.body
175 | end
176 | end
177 |
178 | class EditActionBaseTest < ActionController::TestCase
179 | include UserTestHelper
180 |
181 | def test_expose_the_requested_user
182 | User.expects(:find).with('42').returns(mock_user)
183 | get :edit, params: { id: '42' }
184 |
185 | assert_response :success
186 | assert_equal mock_user, assigns(:user)
187 | end
188 |
189 | def test_controller_should_render_edit
190 | User.stubs(:find).returns(mock_user)
191 | get :edit, params: { id: '42' }
192 |
193 | assert_response :success
194 | assert_equal 'Edit HTML', @response.body.strip
195 | end
196 | end
197 |
198 | class CreateActionBaseTest < ActionController::TestCase
199 | include UserTestHelper
200 |
201 | def test_expose_a_newly_create_user_when_saved_with_success
202 | User.expects(:new).with(build_parameters({'these' => 'params'})).returns(mock_user(save: true))
203 | post :create, params: { user: {these: 'params'} }
204 |
205 | assert_equal mock_user, assigns(:user)
206 | end
207 |
208 | def test_expose_a_newly_create_user_when_saved_with_success_and_role_setted
209 | @controller.class.send(:with_role, :admin)
210 | User.expects(:new).with(build_parameters({'these' => 'params'}), {as: :admin}).returns(mock_user(save: true))
211 | post :create, params: { user: {these: 'params'} }
212 |
213 | assert_equal mock_user, assigns(:user)
214 | end
215 |
216 | def test_expose_a_newly_create_user_when_saved_with_success_and_without_protection_setted
217 | @controller.class.send(:without_protection, true)
218 | User.expects(:new).with(build_parameters({'these' => 'params'}), {without_protection: true}).returns(mock_user(save: true))
219 | post :create, params: { user: {these: 'params'} }
220 |
221 | assert_equal mock_user, assigns(:user)
222 | end
223 |
224 | def test_redirect_to_the_created_user
225 | User.stubs(:new).returns(mock_user(save: true))
226 | @controller.expects(:resource_url).returns('http://test.host/')
227 | post :create, format: :html
228 |
229 | assert_redirected_to 'http://test.host/'
230 | end
231 |
232 | def test_show_flash_message_when_success
233 | User.stubs(:new).returns(mock_user(save: true))
234 | post :create
235 |
236 | assert_equal 'User was successfully created.', flash[:notice]
237 | end
238 |
239 | def test_show_flash_message_with_javascript_request_when_success
240 | User.stubs(:new).returns(mock_user(save: true))
241 | post :create, format: :js
242 |
243 | assert_equal 'User was successfully created.', flash[:notice]
244 | end
245 |
246 | def test_render_new_template_when_user_cannot_be_saved
247 | User.stubs(:new).returns(mock_user(save: false, errors: {some: :error}))
248 | post :create
249 |
250 | assert_response :unprocessable_entity
251 | assert_equal "New HTML", @response.body.strip
252 | end
253 |
254 | def test_dont_show_flash_message_when_user_cannot_be_saved
255 | User.stubs(:new).returns(mock_user(save: false, errors: {some: :error}))
256 | post :create
257 |
258 | assert_empty flash
259 | end
260 | end
261 |
262 | class UpdateActionBaseTest < ActionController::TestCase
263 | include UserTestHelper
264 |
265 | def test_update_the_requested_object
266 | User.expects(:find).with('42').returns(mock_user)
267 | mock_user.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
268 | put :update, params: { id: '42', user: {these: 'params'} }
269 |
270 | assert_equal mock_user, assigns(:user)
271 | end
272 |
273 | def test_update_the_requested_object_when_setted_role
274 | @controller.class.send(:with_role, :admin)
275 | User.expects(:find).with('42').returns(mock_user)
276 | mock_user.expects(:update).with(build_parameters({'these' => 'params'}), {as: :admin}).returns(true)
277 | put :update, params: { id: '42', user: {these: 'params'} }
278 |
279 | assert_equal mock_user, assigns(:user)
280 | end
281 |
282 | def test_update_the_requested_object_when_setted_without_protection
283 | @controller.class.send(:without_protection, true)
284 | User.expects(:find).with('42').returns(mock_user)
285 | mock_user.expects(:update).with(build_parameters({'these' => 'params'}), {without_protection: true}).returns(true)
286 | put :update, params: { id: '42', user: {these: 'params'} }
287 |
288 | assert_equal mock_user, assigns(:user)
289 | end
290 |
291 | def test_redirect_to_the_updated_user
292 | User.stubs(:find).returns(mock_user(update: true))
293 | @controller.expects(:resource_url).returns('http://test.host/')
294 | put :update, params: { id: '42' }
295 |
296 | assert_redirected_to 'http://test.host/'
297 | end
298 |
299 | def test_redirect_to_the_users_list_if_show_undefined
300 | @controller.class.send(:actions, :all, except: :show)
301 | User.stubs(:find).returns(mock_user(update: true))
302 | @controller.expects(:collection_url).returns('http://test.host/')
303 | put :update, params: { id: '42' }
304 |
305 | assert_redirected_to 'http://test.host/'
306 | end
307 |
308 | def test_show_flash_message_when_success
309 | User.stubs(:find).returns(mock_user(update: true))
310 | put :update, params: { id: '42' }
311 |
312 | assert_equal 'User was successfully updated.', flash[:notice]
313 | end
314 |
315 | def test_show_flash_message_with_javascript_request_when_success
316 | User.stubs(:find).returns(mock_user(update: true))
317 | post :update, params: { id: '42' }, format: :js
318 |
319 | assert_equal 'User was successfully updated.', flash[:notice]
320 | end
321 |
322 | def test_render_edit_template_when_user_cannot_be_saved
323 | User.stubs(:find).returns(mock_user(update: false, errors: {some: :error}))
324 | put :update, params: { id: '42' }
325 |
326 | assert_response :unprocessable_entity
327 | assert_equal "Edit HTML", @response.body.strip
328 | end
329 |
330 | def test_dont_show_flash_message_when_user_cannot_be_saved
331 | User.stubs(:find).returns(mock_user(update: false, errors: {some: :error}))
332 | put :update, params: { id: '42' }
333 |
334 | assert_empty flash
335 | end
336 | end
337 |
338 | class DestroyActionBaseTest < ActionController::TestCase
339 | include UserTestHelper
340 |
341 | def test_the_requested_user_is_destroyed
342 | User.expects(:find).with('42').returns(mock_user)
343 | mock_user.expects(:destroy).returns(true)
344 | delete :destroy, params: { id: '42' }
345 |
346 | assert_equal mock_user, assigns(:user)
347 | end
348 |
349 | def test_show_flash_message_when_user_can_be_deleted
350 | User.stubs(:find).returns(mock_user(destroy: true))
351 | delete :destroy, params: { id: '42' }
352 |
353 | assert_equal 'User was successfully destroyed.', flash[:notice]
354 | end
355 |
356 | def test_show_flash_message_with_javascript_request_when_user_can_be_deleted
357 | User.stubs(:find).returns(mock_user(destroy: true))
358 | delete :destroy, params: { id: '42' }, format: :js
359 |
360 | assert_equal 'User was successfully destroyed.', flash[:notice]
361 | end
362 |
363 | def test_show_flash_message_when_user_cannot_be_deleted
364 | User.stubs(:find).returns(mock_user(destroy: false, errors: { fail: true }))
365 | delete :destroy, params: { id: '42' }
366 |
367 | assert_equal 'User could not be destroyed.', flash[:alert]
368 | end
369 |
370 | def test_show_flash_message_with_javascript_request_when_user_cannot_be_deleted
371 | User.stubs(:find).returns(mock_user(destroy: false, errors: { fail: true }))
372 | delete :destroy, params: { id: '42' }, format: :js
373 |
374 | assert_response :unprocessable_entity
375 | assert_equal 'User could not be destroyed.', flash[:alert]
376 | end
377 |
378 | def test_redirects_to_users_list
379 | User.stubs(:find).returns(mock_user(destroy: true))
380 | @controller.expects(:collection_url).returns('http://test.host/')
381 | delete :destroy, params: { id: '42' }
382 |
383 | assert_response :see_other
384 | assert_redirected_to 'http://test.host/'
385 | end
386 |
387 | def test_redirects_to_the_resource_if_cannot_be_destroyed
388 | User.stubs(:find).returns(mock_user(destroy: false))
389 | @controller.expects(:collection_url).returns('http://test.host/')
390 | delete :destroy, params: { id: '42' }
391 |
392 | assert_response :see_other
393 | assert_redirected_to 'http://test.host/'
394 | end
395 | end
396 |
--------------------------------------------------------------------------------
/test/belongs_to_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Post
5 | extend ActiveModel::Naming
6 | end
7 |
8 | class Comment
9 | extend ActiveModel::Naming
10 | end
11 |
12 | class CommentsController < InheritedResources::Base
13 | belongs_to :post
14 | end
15 |
16 | class BelongsToTest < ActionController::TestCase
17 | tests CommentsController
18 |
19 | def setup
20 | draw_routes do
21 | resources :comments, :posts
22 | end
23 |
24 | Post.expects(:find).with('37').returns(mock_post)
25 | mock_post.expects(:comments).returns(Comment)
26 | end
27 |
28 | def teardown
29 | clear_routes
30 | end
31 |
32 | def test_expose_all_comments_as_instance_variable_on_index
33 | Comment.expects(:scoped).returns([mock_comment])
34 | get :index, params: { post_id: '37' }
35 |
36 | assert_equal mock_post, assigns(:post)
37 | assert_equal [mock_comment], assigns(:comments)
38 | end
39 |
40 | def test_expose_the_requested_comment_on_show
41 | Comment.expects(:find).with('42').returns(mock_comment)
42 | get :show, params: { id: '42', post_id: '37' }
43 |
44 | assert_equal mock_post, assigns(:post)
45 | assert_equal mock_comment, assigns(:comment)
46 | end
47 |
48 | def test_expose_a_new_comment_on_new
49 | Comment.expects(:build).returns(mock_comment)
50 | get :new, params: { post_id: '37' }
51 |
52 | assert_equal mock_post, assigns(:post)
53 | assert_equal mock_comment, assigns(:comment)
54 | end
55 |
56 | def test_expose_the_requested_comment_on_edit
57 | Comment.expects(:find).with('42').returns(mock_comment)
58 | get :edit, params: { id: '42', post_id: '37' }
59 |
60 | assert_equal mock_post, assigns(:post)
61 | assert_equal mock_comment, assigns(:comment)
62 | end
63 |
64 | def test_expose_a_newly_create_comment_on_create
65 | Comment.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_comment(save: true))
66 | post :create, params: { post_id: '37', comment: {these: 'params'} }
67 |
68 | assert_equal mock_post, assigns(:post)
69 | assert_equal mock_comment, assigns(:comment)
70 | end
71 |
72 | def test_update_the_requested_object_on_update
73 | Comment.expects(:find).with('42').returns(mock_comment)
74 | mock_comment.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
75 | put :update, params: { id: '42', post_id: '37', comment: {these: 'params'} }
76 |
77 | assert_equal mock_post, assigns(:post)
78 | assert_equal mock_comment, assigns(:comment)
79 | end
80 |
81 | def test_the_requested_comment_is_destroyed_on_destroy
82 | Comment.expects(:find).with('42').returns(mock_comment)
83 | mock_comment.expects(:destroy)
84 | delete :destroy, params: { id: '42', post_id: '37' }
85 |
86 | assert_equal mock_post, assigns(:post)
87 | assert_equal mock_comment, assigns(:comment)
88 | end
89 |
90 | def helper_methods
91 | @controller.class._helpers.instance_methods.map {|m| m.to_s }
92 | end
93 |
94 | def test_helpers
95 | Comment.expects(:scoped).returns([mock_comment])
96 | get :index, params: { post_id: '37' }
97 |
98 | assert_includes helper_methods, 'parent?'
99 | assert @controller.send(:parent?)
100 | assert_equal mock_post, assigns(:post)
101 | assert_includes helper_methods, 'parent'
102 | assert_equal mock_post, @controller.send(:parent)
103 | end
104 |
105 | protected
106 |
107 | def mock_post(stubs={})
108 | @mock_post ||= mock(stubs)
109 | end
110 |
111 | def mock_comment(stubs={})
112 | @mock_comment ||= mock(stubs)
113 | end
114 |
115 | def build_parameters(hash)
116 | ActionController::Parameters.new(hash)
117 | end
118 | end
119 |
120 | class Reply
121 | extend ActiveModel::Naming
122 | end
123 |
124 | class RepliesController < InheritedResources::Base
125 | belongs_to :post
126 | actions :all, except: [:show, :index]
127 | end
128 |
129 | class BelongsToWithRedirectsTest < ActionController::TestCase
130 | tests RepliesController
131 |
132 | def setup
133 | draw_routes do
134 | resources :replies, :posts
135 | end
136 |
137 | Post.expects(:find).with('37').returns(mock_post)
138 | mock_post.expects(:replies).returns(Reply)
139 | end
140 |
141 | def teardown
142 | clear_routes
143 | end
144 |
145 | def test_redirect_to_the_post_on_create_if_show_and_index_undefined
146 | @controller.expects(:parent_url).returns('http://test.host/')
147 | Reply.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_reply(save: true))
148 | post :create, params: { post_id: '37', reply: { these: 'params' } }
149 |
150 | assert_redirected_to 'http://test.host/'
151 | end
152 |
153 | def test_redirect_to_the_post_on_update_if_show_and_index_undefined
154 | Reply.stubs(:find).returns(mock_reply(update: true))
155 | @controller.expects(:parent_url).returns('http://test.host/')
156 | put :update, params: { id: '42', post_id: '37', reply: { these: 'params' } }
157 |
158 | assert_redirected_to 'http://test.host/'
159 | end
160 |
161 | def test_redirect_to_the_post_on_destroy_if_show_and_index_undefined
162 | Reply.expects(:find).with('42').returns(mock_reply)
163 | mock_reply.expects(:destroy)
164 | @controller.expects(:parent_url).returns('http://test.host/')
165 | delete :destroy, params: { id: '42', post_id: '37' }
166 |
167 | assert_redirected_to 'http://test.host/'
168 | end
169 |
170 | protected
171 |
172 | def mock_post(stubs={})
173 | @mock_post ||= mock(stubs)
174 | end
175 |
176 | def mock_reply(stubs={})
177 | @mock_reply ||= mock(stubs)
178 | end
179 |
180 | def build_parameters(hash)
181 | ActionController::Parameters.new(hash)
182 | end
183 | end
184 |
--------------------------------------------------------------------------------
/test/belongs_to_with_shallow_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Post
5 | extend ActiveModel::Naming
6 | end
7 |
8 | class Tag
9 | extend ActiveModel::Naming
10 | end
11 |
12 | class TagsController < InheritedResources::Base
13 | belongs_to :post, shallow: true, finder: :find_by_slug
14 | end
15 |
16 | class BelongsToWithShallowTest < ActionController::TestCase
17 | tests TagsController
18 |
19 | def setup
20 | draw_routes do
21 | resources :tags
22 | end
23 |
24 | Post.expects(:find_by_slug).with('thirty_seven').returns(mock_post)
25 | mock_post.expects(:tags).returns(Tag)
26 |
27 | @controller.stubs(:collection_url).returns('/')
28 | end
29 |
30 | def teardown
31 | clear_routes
32 | end
33 |
34 | def test_expose_all_tags_as_instance_variable_on_index
35 | Tag.expects(:scoped).returns([mock_tag])
36 | get :index, params: { post_id: 'thirty_seven' }
37 |
38 | assert_equal mock_post, assigns(:post)
39 | assert_equal [mock_tag], assigns(:tags)
40 | end
41 |
42 | def test_expose_a_new_tag_on_new
43 | Tag.expects(:build).returns(mock_tag)
44 | get :new, params: { post_id: 'thirty_seven' }
45 |
46 | assert_equal mock_post, assigns(:post)
47 | assert_equal mock_tag, assigns(:tag)
48 | end
49 |
50 | def test_expose_a_newly_create_tag_on_create
51 | Tag.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_tag(save: true))
52 | post :create, params: { post_id: 'thirty_seven', tag: {these: 'params'} }
53 |
54 | assert_equal mock_post, assigns(:post)
55 | assert_equal mock_tag, assigns(:tag)
56 | end
57 |
58 | def test_expose_the_requested_tag_on_show
59 | should_find_parents
60 | get :show, params: { id: '42' }
61 |
62 | assert_equal mock_post, assigns(:post)
63 | assert_equal mock_tag, assigns(:tag)
64 | end
65 |
66 | def test_expose_the_requested_tag_on_edit
67 | should_find_parents
68 | get :edit, params: { id: '42' }
69 |
70 | assert_equal mock_post, assigns(:post)
71 | assert_equal mock_tag, assigns(:tag)
72 | end
73 |
74 | def test_update_the_requested_object_on_update
75 | should_find_parents
76 | mock_tag.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
77 | put :update, params: { id: '42', tag: {these: 'params'} }
78 |
79 | assert_equal mock_post, assigns(:post)
80 | assert_equal mock_tag, assigns(:tag)
81 | end
82 |
83 | def test_the_requested_tag_is_destroyed_on_destroy
84 | should_find_parents
85 | mock_tag.expects(:destroy)
86 | delete :destroy, params: { id: '42', post_id: '37' }
87 |
88 | assert_equal mock_post, assigns(:post)
89 | assert_equal mock_tag, assigns(:tag)
90 | end
91 |
92 | protected
93 |
94 | def should_find_parents
95 | mock_tag.expects(:post).returns(mock_post)
96 | mock_post.expects(:to_param).returns('thirty_seven')
97 | Tag.expects(:find).with('42').twice.returns(mock_tag)
98 | end
99 |
100 | def mock_post(stubs={})
101 | @mock_post ||= mock(stubs)
102 | end
103 |
104 | def mock_tag(stubs={})
105 | @mock_tag ||= mock(stubs)
106 | end
107 |
108 | def build_parameters(hash)
109 | ActionController::Parameters.new(hash)
110 | end
111 | end
112 |
--------------------------------------------------------------------------------
/test/changelog_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class ChangelogTest < ActiveSupport::TestCase
5 | def setup
6 | path = File.join(File.dirname(__dir__), "CHANGELOG.md")
7 | @changelog = File.read(path)
8 | end
9 |
10 | def test_has_definitions_for_all_implicit_links
11 | implicit_link_names = @changelog.scan(/\[([^\]]+)\]\[\]/).flatten.uniq
12 |
13 | implicit_link_names.each do |name|
14 | assert_includes @changelog, "[#{name}]: https"
15 | end
16 | end
17 |
18 | def test_entry_does_end_with_a_punctuation
19 | lines = @changelog.each_line
20 | entries = lines.grep(/^\*/)
21 |
22 | entries.each do |entry|
23 | assert_no_match(/(\.|\:)$/, entry)
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/test/class_methods_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Book; end
5 | class Folder; end
6 |
7 | class BooksController < InheritedResources::Base
8 | custom_actions collection: :search, resource: [:delete]
9 | actions :index, :show
10 | end
11 |
12 | class ReadersController < InheritedResources::Base
13 | actions :all, except: [ :edit, :update ]
14 | end
15 |
16 | class FoldersController < InheritedResources::Base
17 | end
18 |
19 | class Dean
20 | def self.human_name; 'Dean'; end
21 | end
22 |
23 | class DeansController < InheritedResources::Base
24 | belongs_to :school
25 | end
26 |
27 | module Controller
28 | class User; end
29 |
30 | class UsersController < InheritedResources::Base; end
31 |
32 | module Admin
33 | class UsersController < InheritedResources::Base; end
34 | end
35 | end
36 |
37 | class ControllerGroup; end
38 |
39 | module Controller
40 | class GroupsController < InheritedResources::Base; end
41 | end
42 |
43 | module Library
44 | class Base
45 | end
46 |
47 | class Category
48 | end
49 |
50 | class Subcategory
51 | end
52 |
53 | class SubcategoriesController < InheritedResources::Base
54 | end
55 | end
56 |
57 | module MyEngine
58 | class Engine < Rails::Engine
59 | isolate_namespace MyEngine
60 | end
61 |
62 | class PeopleController < InheritedResources::Base; end
63 | end
64 |
65 | module MyNamespace
66 | class PeopleController < InheritedResources::Base; end
67 | end
68 |
69 | module EmptyNamespace; end
70 |
71 | class ActionsClassMethodTest < ActionController::TestCase
72 | tests BooksController
73 |
74 | def setup
75 | draw_routes do
76 | resources :books
77 | end
78 | end
79 |
80 | def teardown
81 | clear_routes
82 | end
83 |
84 | def test_cannot_render_actions
85 | assert_raise AbstractController::ActionNotFound do
86 | get :new
87 | end
88 | end
89 |
90 | def test_actions_are_undefined
91 | action_methods = BooksController.send(:action_methods).map(&:to_sym)
92 |
93 | assert_equal 4, action_methods.size
94 |
95 | [:index, :show, :delete, :search].each do |action|
96 | assert_includes action_methods, action
97 | end
98 |
99 | instance_methods = BooksController.send(:instance_methods).map(&:to_sym)
100 |
101 | [:new, :edit, :create, :update, :destroy].each do |action|
102 | refute_includes instance_methods, action
103 | end
104 | end
105 |
106 | def test_actions_are_undefined_when_except_option_is_given
107 | action_methods = ReadersController.send(:action_methods)
108 |
109 | assert_equal 5, action_methods.size
110 |
111 | ['index', 'new', 'show', 'create', 'destroy'].each do |action|
112 | assert_includes action_methods, action
113 | end
114 | end
115 | end
116 |
117 | class DefaultsClassMethodTest < ActiveSupport::TestCase
118 | def test_resource_class_is_set_to_nil_when_resource_model_cannot_be_found
119 | assert_nil ReadersController.send(:resource_class)
120 | end
121 |
122 | def test_defaults_are_set
123 | assert_equal Folder, FoldersController.send(:resource_class)
124 | assert_equal :folder, FoldersController.send(:resources_configuration)[:self][:instance_name]
125 | assert_equal :folders, FoldersController.send(:resources_configuration)[:self][:collection_name]
126 | end
127 |
128 | def test_defaults_can_be_overwriten
129 | BooksController.send(:defaults, resource_class: String, instance_name: 'string', collection_name: 'strings')
130 |
131 | assert_equal String, BooksController.send(:resource_class)
132 | assert_equal :string, BooksController.send(:resources_configuration)[:self][:instance_name]
133 | assert_equal :strings, BooksController.send(:resources_configuration)[:self][:collection_name]
134 |
135 | BooksController.send(:defaults, class_name: 'Integer', instance_name: :integer, collection_name: :integers)
136 |
137 | assert_equal Integer, BooksController.send(:resource_class)
138 | assert_equal :integer, BooksController.send(:resources_configuration)[:self][:instance_name]
139 | assert_equal :integers, BooksController.send(:resources_configuration)[:self][:collection_name]
140 | end
141 |
142 | def test_defaults_raises_invalid_key
143 | assert_raise ArgumentError do
144 | BooksController.send(:defaults, boom: String)
145 | end
146 | end
147 |
148 | def test_url_helpers_are_recreated_when_defaults_change # rubocop:disable Minitest/NoAssertions
149 | BooksController.expects(:create_resources_url_helpers!).returns(true).once
150 | BooksController.send(:defaults, instance_name: 'string', collection_name: 'strings')
151 | end
152 | end
153 |
154 | class BelongsToErrorsTest < ActiveSupport::TestCase
155 | def test_belongs_to_raise_errors_with_invalid_arguments
156 | assert_raise ArgumentError do
157 | DeansController.send(:belongs_to)
158 | end
159 |
160 | assert_raise ArgumentError do
161 | DeansController.send(:belongs_to, :nice, invalid_key: '')
162 | end
163 | end
164 |
165 | def test_belongs_to_raises_an_error_when_multiple_associations_are_given_with_options
166 | assert_raise ArgumentError do
167 | DeansController.send(:belongs_to, :arguments, :with_options, parent_class: Book)
168 | end
169 | end
170 |
171 | def test_url_helpers_are_recreated_just_once_when_belongs_to_is_called_with_block # rubocop:disable Minitest/NoAssertions
172 | DeansController.expects(:create_resources_url_helpers!).returns(true).once
173 | DeansController.send(:belongs_to, :school) do
174 | belongs_to :association
175 | end
176 | ensure
177 | DeansController.send(:parents_symbols=, [:school])
178 | end
179 |
180 | def test_url_helpers_are_recreated_just_once_when_belongs_to_is_called_with_multiple_blocks # rubocop:disable Minitest/NoAssertions
181 | DeansController.expects(:create_resources_url_helpers!).returns(true).once
182 | DeansController.send(:belongs_to, :school) do
183 | belongs_to :association do
184 | belongs_to :nested
185 | end
186 | end
187 | ensure
188 | DeansController.send(:parents_symbols=, [:school])
189 | end
190 |
191 | def test_belongs_to_for_namespaced_controller_and_namespaced_model_fetches_model_in_the_namespace_firstly
192 | Library::SubcategoriesController.send(:belongs_to, :category)
193 |
194 | assert_equal Library::Category, Library::SubcategoriesController.resources_configuration[:category][:parent_class]
195 | end
196 |
197 | def test_belongs_to_for_namespaced_controller_and_non_namespaced_model_sets_parent_class_properly
198 | Library::SubcategoriesController.send(:belongs_to, :book)
199 |
200 | assert_equal Book, Library::SubcategoriesController.resources_configuration[:book][:parent_class]
201 | end
202 |
203 | def test_belongs_to_for_namespaced_model_sets_parent_class_properly
204 | Library::SubcategoriesController.send(:belongs_to, :library, class_name: 'Library::Base')
205 |
206 | assert_equal Library::Base, Library::SubcategoriesController.resources_configuration[:library][:parent_class]
207 | end
208 |
209 | def test_belongs_to_without_namespace_sets_parent_class_properly
210 | FoldersController.send(:belongs_to, :book)
211 |
212 | assert_equal Book, FoldersController.resources_configuration[:book][:parent_class]
213 | end
214 | end
215 |
216 | class SpecialCasesClassMethodTest < ActionController::TestCase
217 | def test_resource_class_to_corresponding_model_class
218 | assert_equal Controller::User, Controller::UsersController.send(:resource_class)
219 | assert_equal Controller::User, Controller::Admin::UsersController.send(:resource_class)
220 | assert_equal ControllerGroup, Controller::GroupsController.send(:resource_class)
221 | end
222 | end
223 |
224 | class MountableEngineTest < ActiveSupport::TestCase
225 | def test_route_prefix_do_not_include_engine_name
226 | puts MyEngine::PeopleController.send(:resources_configuration)[:self][:route_prefix]
227 |
228 | assert_nil MyEngine::PeopleController.send(:resources_configuration)[:self][:route_prefix]
229 | end
230 |
231 | def test_route_prefix_present_when_parent_module_is_not_a_engine
232 | assert_equal :my_namespace, MyNamespace::PeopleController.send(:resources_configuration)[:self][:route_prefix]
233 | end
234 | end
235 |
236 | class EngineLoadErrorTest < ActiveSupport::TestCase
237 | def test_does_not_crash_on_engine_load_error # rubocop:disable Minitest/NoAssertions
238 | ActiveSupport::Dependencies.autoload_paths << 'test/autoload'
239 |
240 | assert_nil EmptyNamespace.class_eval <<~RUBY
241 | class PeopleController < InheritedResources::Base; end
242 | RUBY
243 | end
244 | end
245 |
--------------------------------------------------------------------------------
/test/customized_base_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Car
5 | extend ActiveModel::Naming
6 | end
7 |
8 | class CarsController < InheritedResources::Base
9 | respond_to :html
10 |
11 | protected
12 |
13 | def collection
14 | @cars ||= Car.get_all
15 | end
16 |
17 | def build_resource
18 | @car ||= Car.create_new(params[:car])
19 | end
20 |
21 | def resource
22 | @car ||= Car.get(params[:id])
23 | end
24 |
25 | def create_resource(resource)
26 | resource.save_successfully
27 | end
28 |
29 | def update_resource(resource, attributes)
30 | resource.update_successfully(*attributes)
31 | end
32 |
33 | def destroy_resource(resource)
34 | resource.destroy_successfully
35 | end
36 | end
37 |
38 | module CarTestHelper
39 | def setup
40 | draw_routes do
41 | resources :cars
42 | end
43 |
44 | @controller = CarsController.new
45 | @controller.request = @request = new_request
46 | @controller.response = @response = new_response
47 | @controller.stubs(:car_url).returns("/")
48 | end
49 |
50 | def teardown
51 | clear_routes
52 | end
53 |
54 | protected
55 |
56 | def new_request
57 | ActionController::TestRequest.create(CarsController)
58 | end
59 |
60 | def new_response
61 | ActionDispatch::TestResponse.create
62 | end
63 |
64 | def mock_car(expectations={})
65 | @mock_car ||= begin
66 | car = mock(expectations.except(:errors))
67 | car.stubs(:class).returns(Car)
68 | car.stubs(:errors).returns(expectations.fetch(:errors, {}))
69 | car
70 | end
71 | end
72 |
73 | def build_parameters(hash)
74 | ActionController::Parameters.new(hash)
75 | end
76 | end
77 |
78 | class IndexActionCustomizedBaseTest < ActionController::TestCase
79 | include CarTestHelper
80 |
81 | def test_expose_all_users_as_instance_variable
82 | Car.expects(:get_all).returns([mock_car])
83 | get :index
84 |
85 | assert_equal [mock_car], assigns(:cars)
86 | end
87 | end
88 |
89 | class ShowActionCustomizedBaseTest < ActionController::TestCase
90 | include CarTestHelper
91 |
92 | def test_expose_the_requested_user
93 | Car.expects(:get).with('42').returns(mock_car)
94 | get :show, params: { id: '42' }
95 |
96 | assert_equal mock_car, assigns(:car)
97 | end
98 | end
99 |
100 | class NewActionCustomizedBaseTest < ActionController::TestCase
101 | include CarTestHelper
102 |
103 | def test_expose_a_new_user
104 | Car.expects(:create_new).returns(mock_car)
105 | get :new
106 |
107 | assert_equal mock_car, assigns(:car)
108 | end
109 | end
110 |
111 | class EditActionCustomizedBaseTest < ActionController::TestCase
112 | include CarTestHelper
113 |
114 | def test_expose_the_requested_user
115 | Car.expects(:get).with('42').returns(mock_car)
116 | get :edit, params: { id: '42' }
117 |
118 | assert_response :success
119 | assert_equal mock_car, assigns(:car)
120 | end
121 | end
122 |
123 | class CreateActionCustomizedBaseTest < ActionController::TestCase
124 | include CarTestHelper
125 |
126 | def test_expose_a_newly_create_user_when_saved_with_success
127 | Car.expects(:create_new).with(build_parameters({'these' => 'params'})).returns(mock_car(save_successfully: true))
128 | post :create, params: { car: {these: 'params'} }
129 |
130 | assert_equal mock_car, assigns(:car)
131 | end
132 |
133 | def test_redirect_to_the_created_user
134 | Car.stubs(:create_new).returns(mock_car(save_successfully: true))
135 | @controller.expects(:resource_url).returns('http://test.host/')
136 | post :create
137 |
138 | assert_redirected_to 'http://test.host/'
139 | end
140 |
141 | def test_render_new_template_when_user_cannot_be_saved
142 | Car.stubs(:create_new).returns(mock_car(save_successfully: false, errors: {some: :error}))
143 | post :create
144 |
145 | assert_response :unprocessable_entity
146 | assert_equal "New HTML", @response.body.strip
147 | end
148 | end
149 |
150 | class UpdateActionCustomizedBaseTest < ActionController::TestCase
151 | include CarTestHelper
152 |
153 | def test_update_the_requested_object
154 | Car.expects(:get).with('42').returns(mock_car)
155 | mock_car.expects(:update_successfully).with(build_parameters({'these' => 'params'})).returns(true)
156 | put :update, params: { id: '42', car: {these: 'params'} }
157 |
158 | assert_equal mock_car, assigns(:car)
159 | end
160 |
161 | def test_redirect_to_the_created_user
162 | Car.stubs(:get).returns(mock_car(update_successfully: true))
163 | @controller.expects(:resource_url).returns('http://test.host/')
164 | put :update, params: { id: '42' }
165 |
166 | assert_redirected_to 'http://test.host/'
167 | end
168 |
169 | def test_render_edit_template_when_user_cannot_be_saved
170 | Car.stubs(:get).returns(mock_car(update_successfully: false, errors: {some: :error}))
171 | put :update, params: { id: '42' }
172 |
173 | assert_response :unprocessable_entity
174 | assert_equal "Edit HTML", @response.body.strip
175 | end
176 | end
177 |
178 | class DestroyActionCustomizedBaseTest < ActionController::TestCase
179 | include CarTestHelper
180 |
181 | def test_the_requested_user_is_destroyed
182 | Car.expects(:get).with('42').returns(mock_car)
183 | mock_car.expects(:destroy_successfully)
184 | delete :destroy, params: { id: '42' }
185 |
186 | assert_equal mock_car, assigns(:car)
187 | end
188 |
189 | def test_show_flash_message_when_user_can_be_deleted
190 | Car.stubs(:get).returns(mock_car(destroy_successfully: true))
191 | delete :destroy, params: { id: '42' }
192 |
193 | assert_equal 'Car was successfully destroyed.', flash[:notice]
194 | end
195 |
196 | def test_show_flash_message_when_cannot_be_deleted
197 | Car.stubs(:get).returns(mock_car(destroy_successfully: false, errors: { fail: true }))
198 | delete :destroy, params: { id: '42' }
199 |
200 | assert_equal 'Car could not be destroyed.', flash[:alert]
201 | end
202 | end
203 |
--------------------------------------------------------------------------------
/test/customized_belongs_to_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class GreatSchool
5 | end
6 |
7 | class Professor
8 | def self.human_name; 'Professor'; end
9 | end
10 |
11 | class ProfessorsController < InheritedResources::Base
12 | belongs_to :school, parent_class: GreatSchool, instance_name: :great_school,
13 | finder: :find_by_title!, param: :school_title
14 | end
15 |
16 | class CustomizedBelongsToTest < ActionController::TestCase
17 | tests ProfessorsController
18 |
19 | def setup
20 | draw_routes do
21 | resources :professors
22 | end
23 |
24 | GreatSchool.expects(:find_by_title!).with('nice').returns(mock_school(professors: Professor))
25 | @controller.stubs(:collection_url).returns('/')
26 | end
27 |
28 | def teardown
29 | clear_routes
30 | end
31 |
32 | def test_expose_the_requested_school_with_chosen_instance_variable_on_index
33 | Professor.stubs(:scoped).returns([mock_professor])
34 | get :index, params: { school_title: 'nice' }
35 |
36 | assert_equal mock_school, assigns(:great_school)
37 | end
38 |
39 | def test_expose_the_requested_school_with_chosen_instance_variable_on_show
40 | Professor.stubs(:find).returns(mock_professor)
41 | get :show, params: { id: 42, school_title: 'nice' }
42 |
43 | assert_equal mock_school, assigns(:great_school)
44 | end
45 |
46 | def test_expose_the_requested_school_with_chosen_instance_variable_on_new
47 | Professor.stubs(:build).returns(mock_professor)
48 | get :new, params: { school_title: 'nice' }
49 |
50 | assert_equal mock_school, assigns(:great_school)
51 | end
52 |
53 | def test_expose_the_requested_school_with_chosen_instance_variable_on_edit
54 | Professor.stubs(:find).returns(mock_professor)
55 | get :edit, params: { id: 42, school_title: 'nice' }
56 |
57 | assert_equal mock_school, assigns(:great_school)
58 | end
59 |
60 | def test_expose_the_requested_school_with_chosen_instance_variable_on_create
61 | Professor.stubs(:build).returns(mock_professor(save: true))
62 | post :create, params: { school_title: 'nice' }
63 |
64 | assert_equal mock_school, assigns(:great_school)
65 | end
66 |
67 | def test_expose_the_requested_school_with_chosen_instance_variable_on_update
68 | Professor.stubs(:find).returns(mock_professor(update: true))
69 | put :update, params: { id: 42, school_title: 'nice' }
70 |
71 | assert_equal mock_school, assigns(:great_school)
72 | end
73 |
74 | def test_expose_the_requested_school_with_chosen_instance_variable_on_destroy
75 | Professor.stubs(:find).returns(mock_professor(destroy: true))
76 | delete :destroy, params: { id: 42, school_title: 'nice' }
77 |
78 | assert_equal mock_school, assigns(:great_school)
79 | end
80 |
81 | protected
82 |
83 | def mock_school(stubs={})
84 | @mock_school ||= mock(stubs)
85 | end
86 |
87 | def mock_professor(stubs={})
88 | @mock_professor ||= mock(stubs)
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/test/customized_redirect_to_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Post;
5 | def self.human_name; 'Post'; end
6 | end
7 |
8 | class PostsController < InheritedResources::Base
9 | actions :all, except: [:show]
10 | end
11 |
12 | class RedirectToIndexWithoutShowTest < ActionController::TestCase
13 | tests PostsController
14 |
15 | def setup
16 | draw_routes do
17 | resources :posts
18 | end
19 | end
20 |
21 | def teardown
22 | clear_routes
23 | end
24 |
25 | def test_redirect_index_url_after_create
26 | Post.stubs(:new).returns(mock_machine(save: true))
27 |
28 | refute_respond_to PostsController, :show
29 | post :create
30 |
31 | assert_redirected_to 'http://test.host/posts'
32 | end
33 |
34 | def test_redirect_to_index_url_after_update
35 | Post.stubs(:find).returns(mock_machine(update: true))
36 |
37 | refute_respond_to PostsController, :show
38 | put :update, params: { id: '42' }
39 |
40 | assert_redirected_to 'http://test.host/posts'
41 | end
42 |
43 | protected
44 |
45 | def mock_machine(stubs={})
46 | @mock_machine ||= mock(stubs)
47 | end
48 | end
49 |
--------------------------------------------------------------------------------
/test/defaults_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Malarz
5 | def self.human_name; 'Painter'; end
6 |
7 | def to_param
8 | self.slug
9 | end
10 | end
11 |
12 | class PaintersController < InheritedResources::Base
13 | defaults instance_name: 'malarz', collection_name: 'malarze',
14 | resource_class: Malarz, route_prefix: nil,
15 | finder: :find_by_slug
16 | end
17 |
18 | class DefaultsTest < ActionController::TestCase
19 | tests PaintersController
20 |
21 | def setup
22 | draw_routes do
23 | resources :painters
24 | end
25 | end
26 |
27 | def teardown
28 | clear_routes
29 | end
30 |
31 | def test_expose_all_painters_as_instance_variable
32 | Malarz.expects(:scoped).returns([mock_painter])
33 | get :index
34 |
35 | assert_equal [mock_painter], assigns(:malarze)
36 | end
37 |
38 | def test_collection_instance_variable_should_not_be_set_if_already_defined
39 | @controller.instance_variable_set(:@malarze, [mock_painter])
40 | Malarz.expects(:scoped).never
41 | get :index
42 |
43 | assert_equal [mock_painter], assigns(:malarze)
44 | end
45 |
46 | def test_expose_the_requested_painter_on_show
47 | Malarz.expects(:find_by_slug).with('forty_two').returns(mock_painter)
48 | get :show, params: { id: 'forty_two' }
49 |
50 | assert_equal mock_painter, assigns(:malarz)
51 | end
52 |
53 | def test_expose_a_new_painter
54 | Malarz.expects(:new).returns(mock_painter)
55 | get :new
56 |
57 | assert_equal mock_painter, assigns(:malarz)
58 | end
59 |
60 | def test_expose_the_requested_painter_on_edit
61 | Malarz.expects(:find_by_slug).with('forty_two').returns(mock_painter)
62 | get :edit, params: { id: 'forty_two' }
63 |
64 | assert_response :success
65 | assert_equal mock_painter, assigns(:malarz)
66 | end
67 |
68 | def test_expose_a_newly_create_painter_when_saved_with_success
69 | Malarz.expects(:new).with(build_parameters({'these' => 'params'})).returns(mock_painter(save: true))
70 | post :create, params: { malarz: {these: 'params'} }
71 |
72 | assert_equal mock_painter, assigns(:malarz)
73 | end
74 |
75 | def test_update_the_requested_object
76 | Malarz.expects(:find_by_slug).with('forty_two').returns(mock_painter)
77 | mock_painter.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
78 | put :update, params: { id: 'forty_two', malarz: {these: 'params'} }
79 |
80 | assert_equal mock_painter, assigns(:malarz)
81 | end
82 |
83 | def test_the_requested_painter_is_destroyed
84 | Malarz.expects(:find_by_slug).with('forty_two').returns(mock_painter)
85 | mock_painter.expects(:destroy)
86 | delete :destroy, params: { id: 'forty_two' }
87 |
88 | assert_equal mock_painter, assigns(:malarz)
89 | end
90 |
91 | protected
92 |
93 | def mock_painter(stubs={})
94 | @mock_painter ||= mock(stubs)
95 | end
96 |
97 | def build_parameters(hash)
98 | ActionController::Parameters.new(hash)
99 | end
100 | end
101 |
102 | class Lecturer
103 | def self.human_name; 'Einstein'; end
104 | end
105 | module University; end
106 | class University::LecturersController < InheritedResources::Base
107 | defaults finder: :find_by_slug
108 | end
109 |
110 | class DefaultsNamespaceTest < ActionController::TestCase
111 | tests University::LecturersController
112 |
113 | def setup
114 | draw_routes do
115 | namespace :university do
116 | resources :lecturers
117 | end
118 | end
119 | end
120 |
121 | def teardown
122 | clear_routes
123 | end
124 |
125 | def test_expose_all_lecturers_as_instance_variable
126 | Lecturer.expects(:scoped).returns([mock_lecturer])
127 | get :index
128 |
129 | assert_equal [mock_lecturer], assigns(:lecturers)
130 | end
131 |
132 | def test_expose_the_requested_lecturer_on_show
133 | Lecturer.expects(:find_by_slug).with('forty_two').returns(mock_lecturer)
134 | get :show, params: { id: 'forty_two' }
135 |
136 | assert_equal mock_lecturer, assigns(:lecturer)
137 | end
138 |
139 | def test_expose_a_new_lecturer
140 | Lecturer.expects(:new).returns(mock_lecturer)
141 | get :new
142 |
143 | assert_equal mock_lecturer, assigns(:lecturer)
144 | end
145 |
146 | def test_expose_the_requested_lecturer_on_edit
147 | Lecturer.expects(:find_by_slug).with('forty_two').returns(mock_lecturer)
148 | get :edit, params: { id: 'forty_two' }
149 |
150 | assert_response :success
151 | assert_equal mock_lecturer, assigns(:lecturer)
152 | end
153 |
154 | def test_expose_a_newly_create_lecturer_when_saved_with_success
155 | Lecturer.expects(:new).with(build_parameters({'these' => 'params'})).returns(mock_lecturer(save: true))
156 | post :create, params: { lecturer: {these: 'params'} }
157 |
158 | assert_equal mock_lecturer, assigns(:lecturer)
159 | end
160 |
161 | def test_update_the_lecturer
162 | Lecturer.expects(:find_by_slug).with('forty_two').returns(mock_lecturer)
163 | mock_lecturer.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
164 | put :update, params: { id: 'forty_two', lecturer: {these: 'params'} }
165 |
166 | assert_equal mock_lecturer, assigns(:lecturer)
167 | end
168 |
169 | def test_the_requested_lecturer_is_destroyed
170 | Lecturer.expects(:find_by_slug).with('forty_two').returns(mock_lecturer)
171 | mock_lecturer.expects(:destroy)
172 | delete :destroy, params: { id: 'forty_two' }
173 |
174 | assert_equal mock_lecturer, assigns(:lecturer)
175 | end
176 |
177 | protected
178 |
179 | def mock_lecturer(stubs={})
180 | @mock_lecturer ||= mock(stubs)
181 | end
182 |
183 | def build_parameters(hash)
184 | ActionController::Parameters.new(hash)
185 | end
186 | end
187 |
188 | class Group
189 | end
190 | class AdminGroup
191 | end
192 | module Admin; end
193 | class Admin::Group
194 | end
195 | class Admin::GroupsController < InheritedResources::Base
196 | end
197 | class NamespacedModelForNamespacedController < ActionController::TestCase
198 | tests Admin::GroupsController
199 |
200 | def test_that_it_picked_the_namespaced_model
201 | # make public so we can test it
202 | Admin::GroupsController.send(:public, :resource_class)
203 |
204 | assert_equal Admin::Group, @controller.resource_class
205 | end
206 | end
207 |
208 | class Role
209 | end
210 | class AdminRole
211 | end
212 | class Admin::RolesController < InheritedResources::Base
213 | end
214 | class TwoPartNameModelForNamespacedController < ActionController::TestCase
215 | tests Admin::RolesController
216 |
217 | def test_that_it_picked_the_camelcased_model
218 | # make public so we can test it
219 | Admin::RolesController.send(:public, :resource_class)
220 |
221 | assert_equal AdminRole, @controller.resource_class
222 | end
223 | end
224 |
225 | class User
226 | end
227 | class Admin::UsersController < InheritedResources::Base
228 | end
229 | class AnotherTwoPartNameModelForNamespacedController < ActionController::TestCase
230 | tests Admin::UsersController
231 |
232 | def test_that_it_picked_the_camelcased_model
233 | # make public so we can test it
234 | Admin::UsersController.send(:public, :resource_class)
235 |
236 | assert_equal User, @controller.resource_class
237 | end
238 |
239 | def test_that_it_got_the_request_params_right
240 | # make public so we can test it
241 | Admin::UsersController.send(:public, :resources_configuration)
242 |
243 | assert_equal 'user', @controller.resources_configuration[:self][:request_name]
244 | end
245 | end
246 |
247 | module MyEngine
248 | class Engine < Rails::Engine
249 | isolate_namespace MyEngine
250 | end
251 |
252 | class Person
253 | extend ActiveModel::Naming
254 | end
255 |
256 | class PeopleController < InheritedResources::Base
257 | defaults resource_class: Person
258 | end
259 | end
260 |
261 | class IsolatedEngineModelController < ActionController::TestCase
262 | tests MyEngine::PeopleController
263 |
264 | def setup
265 | # make public so we can test it
266 | MyEngine::PeopleController.send(:public, *MyEngine::PeopleController.protected_instance_methods)
267 | end
268 |
269 | def test_isolated_model_name
270 | assert_equal 'person', @controller.resources_configuration[:self][:request_name]
271 | end
272 | end
273 |
--------------------------------------------------------------------------------
/test/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | flash:
3 | addresses:
4 | create:
5 | notice: "You created a new address close to {{reference}}."
6 | update:
7 | notice: "Nice! {{resource_name}} was updated with success!"
8 | error: "Oh no! We could not update your address!"
9 | admin:
10 | actions:
11 | create:
12 | notice: "Admin notice message."
13 | error: "Admin error message."
14 | addresses:
15 | create:
16 | notice: "Admin, you created a new address close to {{reference}}."
17 |
--------------------------------------------------------------------------------
/test/nested_belongs_to_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Country
5 | end
6 |
7 | class State
8 | end
9 |
10 | class City
11 | def self.human_name; 'City'; end
12 | end
13 |
14 | class CitiesController < InheritedResources::Base
15 | belongs_to :country, :state
16 | end
17 |
18 | class NestedBelongsToTest < ActionController::TestCase
19 | tests CitiesController
20 |
21 | def setup
22 | draw_routes do
23 | resources :cities
24 | end
25 |
26 | Country.expects(:find).with('13').returns(mock_country)
27 | mock_country.expects(:states).returns(State)
28 | State.expects(:find).with('37').returns(mock_state)
29 | mock_state.expects(:cities).returns(City)
30 |
31 | @controller.stubs(:collection_url).returns('/')
32 | end
33 |
34 | def teardown
35 | clear_routes
36 | end
37 |
38 | def test_assigns_country_and_state_and_city_on_index
39 | City.expects(:scoped).returns([mock_city])
40 | get :index, params: { state_id: '37', country_id: '13' }
41 |
42 | assert_equal mock_country, assigns(:country)
43 | assert_equal mock_state, assigns(:state)
44 | assert_equal [mock_city], assigns(:cities)
45 | end
46 |
47 | def test_assigns_country_and_state_and_city_on_show
48 | City.expects(:find).with('42').returns(mock_city)
49 | get :show, params: { id: '42', state_id: '37', country_id: '13' }
50 |
51 | assert_equal mock_country, assigns(:country)
52 | assert_equal mock_state, assigns(:state)
53 | assert_equal mock_city, assigns(:city)
54 | end
55 |
56 | def test_assigns_country_and_state_and_city_on_new
57 | City.expects(:build).returns(mock_city)
58 | get :new, params: { state_id: '37', country_id: '13' }
59 |
60 | assert_equal mock_country, assigns(:country)
61 | assert_equal mock_state, assigns(:state)
62 | assert_equal mock_city, assigns(:city)
63 | end
64 |
65 | def test_assigns_country_and_state_and_city_on_edit
66 | City.expects(:find).with('42').returns(mock_city)
67 | get :edit, params: { id: '42', state_id: '37', country_id: '13' }
68 |
69 | assert_equal mock_country, assigns(:country)
70 | assert_equal mock_state, assigns(:state)
71 | assert_equal mock_city, assigns(:city)
72 | end
73 |
74 | def test_assigns_country_and_state_and_city_on_create
75 | City.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_city)
76 | mock_city.expects(:save).returns(true)
77 | post :create, params: { state_id: '37', country_id: '13', city: {these: 'params'} }
78 |
79 | assert_equal mock_country, assigns(:country)
80 | assert_equal mock_state, assigns(:state)
81 | assert_equal mock_city, assigns(:city)
82 | end
83 |
84 | def test_assigns_country_and_state_and_city_on_update
85 | City.expects(:find).with('42').returns(mock_city)
86 | mock_city.expects(:update).returns(true)
87 | put :update, params: { id: '42', state_id: '37', country_id: '13', city: {these: 'params'} }
88 |
89 | assert_equal mock_country, assigns(:country)
90 | assert_equal mock_state, assigns(:state)
91 | assert_equal mock_city, assigns(:city)
92 | end
93 |
94 | def test_assigns_country_and_state_and_city_on_destroy
95 | City.expects(:find).with('42').returns(mock_city)
96 | mock_city.expects(:destroy)
97 | delete :destroy, params: { id: '42', state_id: '37', country_id: '13' }
98 |
99 | assert_equal mock_country, assigns(:country)
100 | assert_equal mock_state, assigns(:state)
101 | assert_equal mock_city, assigns(:city)
102 | end
103 |
104 | protected
105 |
106 | def mock_country(stubs={})
107 | @mock_country ||= mock(stubs)
108 | end
109 |
110 | def mock_state(stubs={})
111 | @mock_state ||= mock(stubs)
112 | end
113 |
114 | def mock_city(stubs={})
115 | @mock_city ||= mock(stubs)
116 | end
117 |
118 | def build_parameters(hash)
119 | ActionController::Parameters.new(hash)
120 | end
121 | end
122 |
--------------------------------------------------------------------------------
/test/nested_belongs_to_with_shallow_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Dresser
5 | end
6 |
7 | class Shelf
8 | end
9 |
10 | class Plate
11 | end
12 |
13 | class PlatesController < InheritedResources::Base
14 | belongs_to :dresser, :shelf, shallow: true
15 | end
16 |
17 | class NestedBelongsToWithShallowTest < ActionController::TestCase
18 | tests PlatesController
19 |
20 | def setup
21 | draw_routes do
22 | resources :plates
23 | end
24 |
25 | mock_shelf.expects(:dresser).returns(mock_dresser)
26 | mock_dresser.expects(:to_param).returns('13')
27 |
28 | Dresser.expects(:find).with('13').returns(mock_dresser)
29 | mock_dresser.expects(:shelves).returns(Shelf)
30 | mock_shelf.expects(:plates).returns(Plate)
31 |
32 | @controller.stubs(:collection_url).returns('/')
33 | end
34 |
35 | def teardown
36 | clear_routes
37 | end
38 |
39 | def test_assigns_dresser_and_shelf_and_plate_on_index
40 | Shelf.expects(:find).with('37').twice.returns(mock_shelf)
41 | Plate.expects(:scoped).returns([mock_plate])
42 | get :index, params: { shelf_id: '37' }
43 |
44 | assert_equal mock_dresser, assigns(:dresser)
45 | assert_equal mock_shelf, assigns(:shelf)
46 | assert_equal [mock_plate], assigns(:plates)
47 | end
48 |
49 | def test_assigns_dresser_and_shelf_and_plate_on_show
50 | should_find_parents
51 | get :show, params: { id: '42' }
52 |
53 | assert_equal mock_dresser, assigns(:dresser)
54 | assert_equal mock_shelf, assigns(:shelf)
55 | assert_equal mock_plate, assigns(:plate)
56 | end
57 |
58 | def test_assigns_dresser_and_shelf_and_plate_on_new
59 | Plate.expects(:build).returns(mock_plate)
60 | Shelf.expects(:find).with('37').twice.returns(mock_shelf)
61 | get :new, params: { shelf_id: '37' }
62 |
63 | assert_equal mock_dresser, assigns(:dresser)
64 | assert_equal mock_shelf, assigns(:shelf)
65 | assert_equal mock_plate, assigns(:plate)
66 | end
67 |
68 | def test_assigns_dresser_and_shelf_and_plate_on_edit
69 | should_find_parents
70 | get :edit, params: { id: '42' }
71 |
72 | assert_equal mock_dresser, assigns(:dresser)
73 | assert_equal mock_shelf, assigns(:shelf)
74 | assert_equal mock_plate, assigns(:plate)
75 | end
76 |
77 | def test_assigns_dresser_and_shelf_and_plate_on_create
78 | Shelf.expects(:find).with('37').twice.returns(mock_shelf)
79 |
80 | Plate.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_plate)
81 | mock_plate.expects(:save).returns(true)
82 | post :create, params: { shelf_id: '37', plate: {these: 'params'} }
83 |
84 | assert_equal mock_dresser, assigns(:dresser)
85 | assert_equal mock_shelf, assigns(:shelf)
86 | assert_equal mock_plate, assigns(:plate)
87 | end
88 |
89 | def test_assigns_dresser_and_shelf_and_plate_on_update
90 | should_find_parents
91 | mock_plate.expects(:update).returns(true)
92 | put :update, params: { id: '42', plate: {these: 'params'} }
93 |
94 | assert_equal mock_dresser, assigns(:dresser)
95 | assert_equal mock_shelf, assigns(:shelf)
96 | assert_equal mock_plate, assigns(:plate)
97 | end
98 |
99 | def test_assigns_dresser_and_shelf_and_plate_on_destroy
100 | should_find_parents
101 | mock_plate.expects(:destroy)
102 | delete :destroy, params: { id: '42' }
103 |
104 | assert_equal mock_dresser, assigns(:dresser)
105 | assert_equal mock_shelf, assigns(:shelf)
106 | assert_equal mock_plate, assigns(:plate)
107 | end
108 |
109 | protected
110 |
111 | def should_find_parents
112 | Plate.expects(:find).with('42').returns(mock_plate)
113 | mock_plate.expects(:shelf).returns(mock_shelf)
114 | mock_shelf.expects(:to_param).returns('37')
115 | Plate.expects(:find).with('42').returns(mock_plate)
116 | Shelf.expects(:find).with('37').returns(mock_shelf)
117 | end
118 |
119 | def mock_dresser(stubs={})
120 | @mock_dresser ||= mock(stubs)
121 | end
122 |
123 | def mock_shelf(stubs={})
124 | @mock_shelf ||= mock(stubs)
125 | end
126 |
127 | def mock_plate(stubs={})
128 | @mock_plate ||= mock(stubs)
129 | end
130 |
131 | def build_parameters(hash)
132 | ActionController::Parameters.new(hash)
133 | end
134 | end
135 |
--------------------------------------------------------------------------------
/test/nested_model_with_shallow_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Subfaculty
5 | end
6 |
7 | class Speciality
8 | end
9 |
10 | module Plan
11 | class Group
12 | end
13 |
14 | class Education
15 | end
16 | end
17 |
18 | class GroupsController < InheritedResources::Base
19 | defaults resource_class: Plan::Group, finder: :find_by_slug
20 | belongs_to :subfaculty, shallow: true do
21 | belongs_to :speciality
22 | end
23 | end
24 |
25 | class EducationsController < InheritedResources::Base
26 | defaults resource_class: Plan::Education
27 | belongs_to :subfaculty, shallow: true do
28 | belongs_to :speciality do
29 | belongs_to :group, parent_class: Plan::Group,
30 | instance_name: :plan_group,
31 | param: :group_id,
32 | finder: :find_by_slug
33 | end
34 | end
35 | end
36 |
37 | class NestedModelWithShallowTest < ActionController::TestCase
38 | tests GroupsController
39 |
40 | def setup
41 | draw_routes do
42 | resources :groups
43 | end
44 |
45 | mock_speciality.expects(:subfaculty).returns(mock_subfaculty)
46 | mock_subfaculty.expects(:to_param).returns('13')
47 |
48 | Subfaculty.expects(:find).with('13').returns(mock_subfaculty)
49 | mock_subfaculty.expects(:specialities).returns(Speciality)
50 | mock_speciality.expects(:groups).returns(Plan::Group)
51 | end
52 |
53 | def teardown
54 | clear_routes
55 | end
56 |
57 | def test_assigns_subfaculty_and_speciality_and_group_on_edit
58 | should_find_parents
59 | get :edit, params: { id: 'forty_two' }
60 |
61 | assert_equal mock_subfaculty, assigns(:subfaculty)
62 | assert_equal mock_speciality, assigns(:speciality)
63 | assert_equal mock_group, assigns(:group)
64 | end
65 |
66 | def test_expose_a_newly_create_group_with_speciality
67 | Speciality.expects(:find).with('37').twice.returns(mock_speciality)
68 | Plan::Group.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_group(save: true))
69 | post :create, params: { speciality_id: '37', group: {'these' => 'params'} }
70 |
71 | assert_equal mock_group, assigns(:group)
72 | end
73 |
74 | def test_expose_a_update_group_with_speciality
75 | should_find_parents
76 | mock_group.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
77 | post :update, params: { id: 'forty_two', group: {'these' => 'params'} }
78 |
79 | assert_equal mock_group, assigns(:group)
80 | end
81 |
82 | protected
83 |
84 | def should_find_parents
85 | Plan::Group.expects(:find_by_slug).with('forty_two').returns(mock_group)
86 | mock_group.expects(:speciality).returns(mock_speciality)
87 | mock_speciality.expects(:to_param).returns('37')
88 | Plan::Group.expects(:find_by_slug).with('forty_two').returns(mock_group)
89 | Speciality.expects(:find).with('37').returns(mock_speciality)
90 | end
91 |
92 | def mock_group(stubs={})
93 | @mock_group ||= mock(stubs)
94 | end
95 |
96 | def mock_speciality(stubs={})
97 | @mock_speciality ||= mock(stubs)
98 | end
99 |
100 | def mock_subfaculty(stubs={})
101 | @mock_subfaculty ||= mock(stubs)
102 | end
103 |
104 | def build_parameters(hash)
105 | ActionController::Parameters.new(hash)
106 | end
107 | end
108 |
109 | class TwoNestedModelWithShallowTest < ActionController::TestCase
110 | tests EducationsController
111 |
112 | def setup
113 | draw_routes do
114 | resources :educations
115 | end
116 |
117 | mock_speciality.expects(:subfaculty).returns(mock_subfaculty)
118 | mock_subfaculty.expects(:to_param).returns('13')
119 | Subfaculty.expects(:find).with('13').returns(mock_subfaculty)
120 | mock_subfaculty.expects(:specialities).returns(Speciality)
121 | mock_speciality.expects(:groups).returns(Plan::Group)
122 | end
123 |
124 | def teardown
125 | clear_routes
126 | end
127 |
128 | def test_assigns_subfaculty_and_speciality_and_group_on_new
129 | should_find_parents
130 | get :new, params: { group_id: 'forty_two' }
131 |
132 | assert_equal mock_subfaculty, assigns(:subfaculty)
133 | assert_equal mock_speciality, assigns(:speciality)
134 | assert_equal mock_group, assigns(:plan_group)
135 | assert_equal mock_education, assigns(:education)
136 | end
137 |
138 | protected
139 |
140 | def should_find_parents
141 | Plan::Group.expects(:find_by_slug).with('forty_two').returns(mock_group)
142 | mock_group.expects(:speciality).returns(mock_speciality)
143 | mock_group.expects(:educations).returns(mock_education)
144 | mock_education.expects(:build).returns(mock_education)
145 | mock_speciality.expects(:to_param).returns('37')
146 | Plan::Group.expects(:find_by_slug).with('forty_two').returns(mock_group)
147 | Speciality.expects(:find).with('37').returns(mock_speciality)
148 | end
149 |
150 | def mock_group(stubs={})
151 | @mock_group ||= mock(stubs)
152 | end
153 |
154 | def mock_education(stubs={})
155 | @mock_education ||= mock(stubs)
156 | end
157 |
158 | def mock_speciality(stubs={})
159 | @mock_speciality ||= mock(stubs)
160 | end
161 |
162 | def mock_subfaculty(stubs={})
163 | @mock_subfaculty ||= mock(stubs)
164 | end
165 | end
166 |
--------------------------------------------------------------------------------
/test/nested_singleton_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | # This test file is instead to test the how controller flow and actions
5 | # using a belongs_to association. This is done using mocks a la rspec.
6 | #
7 | class Party
8 | extend ActiveModel::Naming
9 | end
10 |
11 | class Venue
12 | extend ActiveModel::Naming
13 | end
14 |
15 | class Address
16 | extend ActiveModel::Naming
17 | end
18 |
19 | ActiveSupport::Inflector.inflections do |inflect|
20 | inflect.singular "address", "address"
21 | inflect.plural "address", "addresses"
22 | end
23 |
24 | class VenueController < InheritedResources::Base
25 | defaults singleton: true
26 | belongs_to :party
27 | end
28 |
29 | # for the slightly pathological
30 | # /party/37/venue/address case
31 | class AddressController < InheritedResources::Base
32 | defaults singleton: true
33 | belongs_to :party do
34 | belongs_to :venue, singleton: true
35 | end
36 | end
37 |
38 | #and the more pathological case
39 | class GeolocationController < InheritedResources::Base
40 | defaults singleton: true
41 | belongs_to :party do
42 | belongs_to :venue, singleton: true do
43 | belongs_to :address, singleton: true
44 | end
45 | end
46 | end
47 |
48 | class NestedSingletonTest < ActionController::TestCase
49 | tests AddressController
50 |
51 | def setup
52 | draw_routes do
53 | resources :party do
54 | resource :venue, controller: :venue do
55 | resource :address, controller: :address do
56 | resource :geolocation, controller: :geolocation
57 | end
58 | end
59 | end
60 | end
61 | end
62 |
63 | def teardown
64 | clear_routes
65 | end
66 |
67 | def test_does_not_break_parent_controller
68 | #this is kind of tacky, but seems to work
69 | old_controller = @controller
70 | @controller = VenueController.new
71 | Party.expects(:find).with('37').returns(mock_party)
72 | mock_party.expects(:venue).returns(mock_venue)
73 | get :show, params: { party_id: '37' }
74 |
75 | assert_equal mock_party, assigns(:party)
76 | assert_equal mock_venue, assigns(:venue)
77 | ensure
78 | @controller = old_controller
79 | end
80 |
81 | def test_does_not_break_child_controller
82 | #this is kind of tacky, but seems to work
83 | old_controller = @controller
84 | @controller = GeolocationController.new
85 | Party.expects(:find).with('37').returns(mock_party)
86 | mock_party.expects(:venue).returns(mock_venue)
87 | mock_venue.expects(:address).returns(mock_address)
88 | mock_address.expects(:geolocation).returns(mock_geolocation)
89 | get :show, params: { party_id: '37' }
90 |
91 | assert_equal mock_party, assigns(:party)
92 | assert_equal mock_venue, assigns(:venue)
93 | assert_equal mock_address, assigns(:address)
94 | assert_equal mock_geolocation, assigns(:geolocation)
95 | ensure
96 | @controller = old_controller
97 | end
98 |
99 | def test_expose_a_new_address_on_new
100 | Party.expects(:find).with('37').returns(mock_party)
101 | mock_party.expects(:venue).returns(mock_venue)
102 | mock_venue.expects(:build_address).returns(mock_address)
103 | get :new, params: { party_id: '37' }
104 |
105 | assert_equal mock_party, assigns(:party)
106 | assert_equal mock_venue, assigns(:venue)
107 | assert_equal mock_address, assigns(:address)
108 | end
109 |
110 | def test_expose_the_address_on_edit
111 | Party.expects(:find).with('37').returns(mock_party)
112 | mock_party.expects(:venue).returns(mock_venue)
113 | mock_venue.expects(:address).returns(mock_address)
114 | get :edit, params: { party_id: '37' }
115 |
116 | assert_equal mock_party, assigns(:party)
117 | assert_equal mock_venue, assigns(:venue)
118 | assert_equal mock_address, assigns(:address)
119 | assert_response :success
120 | end
121 |
122 | def test_expose_the_address_on_show
123 | Party.expects(:find).with('37').returns(mock_party)
124 | mock_party.expects(:venue).returns(mock_venue)
125 | mock_venue.expects(:address).returns(mock_address)
126 | get :show, params: { party_id: '37' }
127 |
128 | assert_equal mock_party, assigns(:party)
129 | assert_equal mock_venue, assigns(:venue)
130 | assert_equal mock_address, assigns(:address)
131 | assert_response :success
132 | end
133 |
134 | def test_expose_a_newly_create_address_on_create
135 | Party.expects(:find).with('37').returns(mock_party)
136 | mock_party.expects(:venue).returns(mock_venue)
137 | mock_venue.expects(:build_address).with(build_parameters({'these' => 'params'})).returns(mock_address(save: true))
138 | post :create, params: { party_id: '37', address: {these: 'params'} }
139 |
140 | assert_equal mock_party, assigns(:party)
141 | assert_equal mock_venue, assigns(:venue)
142 | assert_equal mock_address, assigns(:address)
143 | end
144 |
145 | def test_update_the_requested_object_on_update
146 | Party.expects(:find).with('37').returns(mock_party)
147 | mock_party.expects(:venue).returns(mock_venue(address: mock_address))
148 | mock_address.expects(:update).with(build_parameters({'these' => 'params'})).returns(mock_address(save: true))
149 | post :update, params: { party_id: '37', address: {these: 'params'} }
150 |
151 | assert_equal mock_party, assigns(:party)
152 | assert_equal mock_venue, assigns(:venue)
153 | assert_equal mock_address, assigns(:address)
154 | end
155 |
156 | def test_the_requested_manager_is_destroyed_on_destroy
157 | Party.expects(:find).with('37').returns(mock_party)
158 | mock_party.expects(:venue).returns(mock_venue)
159 | mock_venue.expects(:address).returns(mock_address)
160 | @controller.expects(:parent_url).returns('http://test.host/')
161 | mock_address.expects(:destroy)
162 | delete :destroy, params: { party_id: '37' }
163 |
164 | assert_equal mock_party, assigns(:party)
165 | assert_equal mock_venue, assigns(:venue)
166 | assert_equal mock_address, assigns(:address)
167 | end
168 |
169 | protected
170 |
171 | def mock_party(stubs={})
172 | @mock_party ||= mock('party',stubs)
173 | end
174 |
175 | def mock_venue(stubs={})
176 | @mock_venue ||= mock('venue',stubs)
177 | end
178 |
179 | def mock_address(stubs={})
180 | @mock_address ||= mock('address',stubs)
181 | end
182 |
183 | def mock_geolocation(stubs={})
184 | @mock_geolocation ||= mock('geolocation', stubs)
185 | end
186 |
187 | def build_parameters(hash)
188 | ActionController::Parameters.new(hash)
189 | end
190 | end
191 |
--------------------------------------------------------------------------------
/test/optional_belongs_to_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Brands; end
5 | class Category; end
6 |
7 | class Product
8 | def self.human_name; 'Product'; end
9 | end
10 |
11 | class ProductsController < InheritedResources::Base
12 | belongs_to :brand, :category, polymorphic: true, optional: true
13 | end
14 |
15 | class OptionalTest < ActionController::TestCase
16 | tests ProductsController
17 |
18 | def setup
19 | draw_routes do
20 | resources :products
21 | end
22 |
23 | @controller.stubs(:resource_url).returns('/')
24 | end
25 |
26 | def teardown
27 | clear_routes
28 | end
29 |
30 | def test_expose_all_products_as_instance_variable_with_category
31 | Category.expects(:find).with('37').returns(mock_category)
32 | mock_category.expects(:products).returns(Product)
33 | Product.expects(:scoped).returns([mock_product])
34 | get :index, params: { category_id: '37' }
35 |
36 | assert_equal mock_category, assigns(:category)
37 | assert_equal [mock_product], assigns(:products)
38 | end
39 |
40 | def test_expose_all_products_as_instance_variable_without_category
41 | Product.expects(:scoped).returns([mock_product])
42 | get :index
43 |
44 | assert_nil assigns(:category)
45 | assert_equal [mock_product], assigns(:products)
46 | end
47 |
48 | def test_expose_the_requested_product_with_category
49 | Category.expects(:find).with('37').returns(mock_category)
50 | mock_category.expects(:products).returns(Product)
51 | Product.expects(:find).with('42').returns(mock_product)
52 | get :show, params: { id: '42', category_id: '37' }
53 |
54 | assert_equal mock_category, assigns(:category)
55 | assert_equal mock_product, assigns(:product)
56 | end
57 |
58 | def test_expose_the_requested_product_without_category
59 | Product.expects(:find).with('42').returns(mock_product)
60 | get :show, params: { id: '42' }
61 |
62 | assert_nil assigns(:category)
63 | assert_equal mock_product, assigns(:product)
64 | end
65 |
66 | def test_expose_a_new_product_with_category
67 | Category.expects(:find).with('37').returns(mock_category)
68 | mock_category.expects(:products).returns(Product)
69 | Product.expects(:build).returns(mock_product)
70 | get :new, params: { category_id: '37' }
71 |
72 | assert_equal mock_category, assigns(:category)
73 | assert_equal mock_product, assigns(:product)
74 | end
75 |
76 | def test_expose_a_new_product_without_category
77 | Product.expects(:new).returns(mock_product)
78 | get :new
79 |
80 | assert_nil assigns(:category)
81 | assert_equal mock_product, assigns(:product)
82 | end
83 |
84 | def test_expose_the_requested_product_for_edition_with_category
85 | Category.expects(:find).with('37').returns(mock_category)
86 | mock_category.expects(:products).returns(Product)
87 | Product.expects(:find).with('42').returns(mock_product)
88 | get :edit, params: { id: '42', category_id: '37' }
89 |
90 | assert_equal mock_category, assigns(:category)
91 | assert_equal mock_product, assigns(:product)
92 | end
93 |
94 | def test_expose_the_requested_product_for_edition_without_category
95 | Product.expects(:find).with('42').returns(mock_product)
96 | get :edit, params: { id: '42' }
97 |
98 | assert_nil assigns(:category)
99 | assert_equal mock_product, assigns(:product)
100 | end
101 |
102 | def test_expose_a_newly_create_product_with_category
103 | Category.expects(:find).with('37').returns(mock_category)
104 | mock_category.expects(:products).returns(Product)
105 | Product.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_product(save: true))
106 | post :create, params: { category_id: '37', product: {these: 'params'} }
107 |
108 | assert_equal mock_category, assigns(:category)
109 | assert_equal mock_product, assigns(:product)
110 | end
111 |
112 | def test_expose_a_newly_create_product_without_category
113 | Product.expects(:new).with(build_parameters({'these' => 'params'})).returns(mock_product(save: true))
114 | post :create, params: { product: {these: 'params'} }
115 |
116 | assert_nil assigns(:category)
117 | assert_equal mock_product, assigns(:product)
118 | end
119 |
120 | def test_update_the_requested_object_with_category
121 | Category.expects(:find).with('37').returns(mock_category)
122 | mock_category.expects(:products).returns(Product)
123 | Product.expects(:find).with('42').returns(mock_product)
124 | mock_product.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
125 |
126 | put :update, params: { id: '42', category_id: '37', product: {these: 'params'} }
127 |
128 | assert_equal mock_category, assigns(:category)
129 | assert_equal mock_product, assigns(:product)
130 | end
131 |
132 | def test_update_the_requested_object_without_category
133 | Product.expects(:find).with('42').returns(mock_product)
134 | mock_product.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
135 |
136 | put :update, params: { id: '42', product: {these: 'params'} }
137 |
138 | assert_nil assigns(:category)
139 | assert_equal mock_product, assigns(:product)
140 | end
141 |
142 | def test_the_requested_product_is_destroyed_with_category
143 | Category.expects(:find).with('37').returns(mock_category)
144 | mock_category.expects(:products).returns(Product)
145 | Product.expects(:find).with('42').returns(mock_product)
146 | mock_product.expects(:destroy).returns(true)
147 | @controller.expects(:collection_url).returns('/')
148 |
149 | delete :destroy, params: { id: '42', category_id: '37' }
150 |
151 | assert_equal mock_category, assigns(:category)
152 | assert_equal mock_product, assigns(:product)
153 | end
154 |
155 | def test_the_requested_product_is_destroyed_without_category
156 | Product.expects(:find).with('42').returns(mock_product)
157 | mock_product.expects(:destroy).returns(true)
158 | @controller.expects(:collection_url).returns('/')
159 |
160 | delete :destroy, params: { id: '42' }
161 |
162 | assert_nil assigns(:category)
163 | assert_equal mock_product, assigns(:product)
164 | end
165 |
166 | def test_polymorphic_helpers
167 | Product.expects(:scoped).returns([mock_product])
168 | get :index
169 |
170 | refute @controller.send(:parent?)
171 | assert_nil assigns(:parent_type)
172 | assert_nil @controller.send(:parent_type)
173 | assert_nil @controller.send(:parent_class)
174 | assert_nil assigns(:category)
175 | assert_nil @controller.send(:parent)
176 | end
177 |
178 | protected
179 |
180 | def mock_category(stubs={})
181 | @mock_category ||= mock(stubs)
182 | end
183 |
184 | def mock_product(stubs={})
185 | @mock_product ||= mock(stubs)
186 | end
187 |
188 | def build_parameters(hash)
189 | ActionController::Parameters.new(hash)
190 | end
191 | end
192 |
--------------------------------------------------------------------------------
/test/parent_controller_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | def force_parent_controller(value)
5 | InheritedResources.send(:remove_const, :Base)
6 | InheritedResources.parent_controller = value
7 | load File.join(__dir__, '..', 'app', 'controllers', 'inherited_resources', 'base.rb')
8 | end
9 |
10 | class ParentControllerTest < ActionController::TestCase
11 | def test_setting_parent_controller
12 | original_parent = InheritedResources::Base.superclass
13 |
14 | assert_equal ApplicationController, original_parent
15 |
16 | force_parent_controller('ActionController::Base')
17 |
18 | assert_equal ActionController::Base, InheritedResources::Base.superclass
19 | ensure
20 | force_parent_controller(original_parent.to_s) # restore original parent
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/test/polymorphic_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Factory; end
5 | class Company; end
6 | class User; end
7 | class Photo; end
8 |
9 | class Employee
10 | def self.human_name; 'Employee'; end
11 | end
12 |
13 | class EmployeesController < InheritedResources::Base
14 | belongs_to :factory, :company, polymorphic: true
15 | end
16 |
17 | class PhotosController < InheritedResources::Base
18 | belongs_to :user, :task, polymorphic: true
19 |
20 | def index
21 | parent
22 | # Overwrite index
23 | end
24 | end
25 |
26 | class PolymorphicFactoriesTest < ActionController::TestCase
27 | tests EmployeesController
28 |
29 | def setup
30 | draw_routes do
31 | resources :employees
32 | end
33 |
34 | Factory.expects(:find).with('37').returns(mock_factory)
35 | mock_factory.expects(:employees).returns(Employee)
36 |
37 | @controller.stubs(:resource_url).returns('/')
38 | @controller.stubs(:collection_url).returns('/')
39 | end
40 |
41 | def teardown
42 | clear_routes
43 | end
44 |
45 | def test_expose_all_employees_as_instance_variable_on_index
46 | Employee.expects(:scoped).returns([mock_employee])
47 | get :index, params: { factory_id: '37' }
48 |
49 | assert_equal mock_factory, assigns(:factory)
50 | assert_equal [mock_employee], assigns(:employees)
51 | end
52 |
53 | def test_expose_the_requested_employee_on_show
54 | Employee.expects(:find).with('42').returns(mock_employee)
55 | get :show, params: { id: '42', factory_id: '37' }
56 |
57 | assert_equal mock_factory, assigns(:factory)
58 | assert_equal mock_employee, assigns(:employee)
59 | end
60 |
61 | def test_expose_a_new_employee_on_new
62 | Employee.expects(:build).returns(mock_employee)
63 | get :new, params: { factory_id: '37' }
64 |
65 | assert_equal mock_factory, assigns(:factory)
66 | assert_equal mock_employee, assigns(:employee)
67 | end
68 |
69 | def test_expose_the_requested_employee_on_edit
70 | Employee.expects(:find).with('42').returns(mock_employee)
71 | get :edit, params: { id: '42', factory_id: '37' }
72 |
73 | assert_equal mock_factory, assigns(:factory)
74 | assert_equal mock_employee, assigns(:employee)
75 | assert_response :success
76 | end
77 |
78 | def test_expose_a_newly_create_employee_on_create
79 | Employee.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_employee(save: true))
80 | post :create, params: { factory_id: '37', employee: {these: 'params'} }
81 |
82 | assert_equal mock_factory, assigns(:factory)
83 | assert_equal mock_employee, assigns(:employee)
84 | end
85 |
86 | def test_update_the_requested_object_on_update
87 | Employee.expects(:find).with('42').returns(mock_employee)
88 | mock_employee.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
89 | put :update, params: { id: '42', factory_id: '37', employee: {these: 'params'} }
90 |
91 | assert_equal mock_factory, assigns(:factory)
92 | assert_equal mock_employee, assigns(:employee)
93 | end
94 |
95 | def test_the_requested_employee_is_destroyed_on_destroy
96 | Employee.expects(:find).with('42').returns(mock_employee)
97 | mock_employee.expects(:destroy)
98 | delete :destroy, params: { id: '42', factory_id: '37' }
99 |
100 | assert_equal mock_factory, assigns(:factory)
101 | assert_equal mock_employee, assigns(:employee)
102 | end
103 |
104 | def test_polymorphic_helpers
105 | mock_factory.stubs(:class).returns(Factory)
106 |
107 | Employee.expects(:scoped).returns([mock_employee])
108 | get :index, params: { factory_id: '37' }
109 |
110 | assert @controller.send(:parent?)
111 | assert_equal :factory, assigns(:parent_type)
112 | assert_equal :factory, @controller.send(:parent_type)
113 | assert_equal Factory, @controller.send(:parent_class)
114 | assert_equal mock_factory, assigns(:factory)
115 | assert_equal mock_factory, @controller.send(:parent)
116 | end
117 |
118 | protected
119 |
120 | def mock_factory(stubs={})
121 | @mock_factory ||= mock(stubs)
122 | end
123 |
124 | def mock_employee(stubs={})
125 | @mock_employee ||= mock(stubs)
126 | end
127 |
128 | def build_parameters(hash)
129 | ActionController::Parameters.new(hash)
130 | end
131 | end
132 |
133 | class PolymorphicCompanyTest < ActionController::TestCase
134 | tests EmployeesController
135 |
136 | def setup
137 | draw_routes do
138 | resources :employees
139 | end
140 |
141 | Company.expects(:find).with('37').returns(mock_company)
142 | mock_company.expects(:employees).returns(Employee)
143 |
144 | @controller.stubs(:resource_url).returns('/')
145 | @controller.stubs(:collection_url).returns('/')
146 | end
147 |
148 | def teardown
149 | clear_routes
150 | end
151 |
152 | def test_expose_all_employees_as_instance_variable_on_index
153 | Employee.expects(:scoped).returns([mock_employee])
154 | get :index, params: { company_id: '37' }
155 |
156 | assert_equal mock_company, assigns(:company)
157 | assert_equal [mock_employee], assigns(:employees)
158 | end
159 |
160 | def test_expose_the_requested_employee_on_show
161 | Employee.expects(:find).with('42').returns(mock_employee)
162 | get :show, params: { id: '42', company_id: '37' }
163 |
164 | assert_equal mock_company, assigns(:company)
165 | assert_equal mock_employee, assigns(:employee)
166 | end
167 |
168 | def test_expose_a_new_employee_on_new
169 | Employee.expects(:build).returns(mock_employee)
170 | get :new, params: { company_id: '37' }
171 |
172 | assert_equal mock_company, assigns(:company)
173 | assert_equal mock_employee, assigns(:employee)
174 | end
175 |
176 | def test_expose_the_requested_employee_on_edit
177 | Employee.expects(:find).with('42').returns(mock_employee)
178 | get :edit, params: { id: '42', company_id: '37' }
179 |
180 | assert_equal mock_company, assigns(:company)
181 | assert_equal mock_employee, assigns(:employee)
182 | assert_response :success
183 | end
184 |
185 | def test_expose_a_newly_create_employee_on_create
186 | Employee.expects(:build).with(build_parameters({'these' => 'params'})).returns(mock_employee(save: true))
187 | post :create, params: { company_id: '37', employee: {these: 'params'} }
188 |
189 | assert_equal mock_company, assigns(:company)
190 | assert_equal mock_employee, assigns(:employee)
191 | end
192 |
193 | def test_update_the_requested_object_on_update
194 | Employee.expects(:find).with('42').returns(mock_employee)
195 | mock_employee.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
196 | put :update, params: { id: '42', company_id: '37', employee: {these: 'params'} }
197 |
198 | assert_equal mock_company, assigns(:company)
199 | assert_equal mock_employee, assigns(:employee)
200 | end
201 |
202 | def test_the_requested_employee_is_destroyed_on_destroy
203 | Employee.expects(:find).with('42').returns(mock_employee)
204 | mock_employee.expects(:destroy)
205 | delete :destroy, params: { id: '42', company_id: '37' }
206 |
207 | assert_equal mock_company, assigns(:company)
208 | assert_equal mock_employee, assigns(:employee)
209 | end
210 |
211 | def test_polymorphic_helpers
212 | mock_company.stubs(:class).returns(Company)
213 |
214 | Employee.expects(:scoped).returns([mock_employee])
215 | get :index, params: { company_id: '37' }
216 |
217 | assert @controller.send(:parent?)
218 | assert_equal :company, assigns(:parent_type)
219 | assert_equal :company, @controller.send(:parent_type)
220 | assert_equal Company, @controller.send(:parent_class)
221 | assert_equal mock_company, assigns(:company)
222 | assert_equal mock_company, @controller.send(:parent)
223 | end
224 |
225 | protected
226 |
227 | def mock_company(stubs={})
228 | @mock_company ||= mock(stubs)
229 | end
230 |
231 | def mock_employee(stubs={})
232 | @mock_employee ||= mock(stubs)
233 | end
234 |
235 | def build_parameters(hash)
236 | ActionController::Parameters.new(hash)
237 | end
238 | end
239 |
240 | class PolymorphicPhotosTest < ActionController::TestCase
241 | tests PhotosController
242 |
243 | def setup
244 | draw_routes do
245 | resources :photos
246 | end
247 |
248 | User.expects(:find).with('37').returns(mock_user)
249 | end
250 |
251 | def teardown
252 | clear_routes
253 | end
254 |
255 | def test_parent_as_instance_variable_on_index_when_method_overwritten
256 | get :index, params: { user_id: '37' }
257 |
258 | assert_equal mock_user, assigns(:user)
259 | end
260 |
261 | protected
262 |
263 | def mock_user(stubs={})
264 | @mock_user ||= mock(stubs)
265 | end
266 | end
267 |
--------------------------------------------------------------------------------
/test/redirect_to_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Machine;
5 | def self.human_name; 'Machine'; end
6 | end
7 |
8 | class MachinesController < InheritedResources::Base
9 | def create
10 | create!{ complex_url(:create, true, true) }
11 | end
12 |
13 | def update
14 | update!{ complex_url(:update, false, false) }
15 | end
16 |
17 | def destroy
18 | destroy!{ complex_url(:destroy, true, false) }
19 | end
20 |
21 | protected
22 |
23 | def complex_url(name, arg2, arg3)
24 | 'http://test.host/' + name.to_s
25 | end
26 | end
27 |
28 | class RedirectToWithBlockTest < ActionController::TestCase
29 | tests MachinesController
30 |
31 | def setup
32 | draw_routes do
33 | resources :machines
34 | end
35 | end
36 |
37 | def teardown
38 | clear_routes
39 | end
40 |
41 | def test_redirect_to_the_given_url_on_create
42 | Machine.stubs(:new).returns(mock_machine(save: true))
43 | post :create
44 |
45 | assert_redirected_to 'http://test.host/create'
46 | end
47 |
48 | def test_redirect_to_the_given_url_on_update
49 | Machine.stubs(:find).returns(mock_machine(update: true))
50 | put :update, params: { id: '42' }
51 |
52 | assert_redirected_to 'http://test.host/update'
53 | end
54 |
55 | def test_redirect_to_the_given_url_on_destroy
56 | Machine.stubs(:find).returns(mock_machine(destroy: true))
57 | delete :destroy, params: { id: '42' }
58 |
59 | assert_redirected_to 'http://test.host/destroy'
60 | end
61 |
62 | protected
63 |
64 | def mock_machine(stubs={})
65 | @mock_machine ||= mock(stubs)
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/test/singleton_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | # This test file is instead to test the how controller flow and actions
5 | # using a belongs_to association. This is done using mocks a la rspec.
6 | #
7 | class Store
8 | extend ActiveModel::Naming
9 | end
10 |
11 | class Manager
12 | extend ActiveModel::Naming
13 | end
14 |
15 | class ManagersController < InheritedResources::Base
16 | defaults singleton: true
17 | belongs_to :store
18 | end
19 |
20 | class SingletonTest < ActionController::TestCase
21 | tests ManagersController
22 |
23 | def setup
24 | draw_routes do
25 | resources :store do
26 | resource :manager
27 | end
28 | end
29 | end
30 |
31 | def teardown
32 | clear_routes
33 | end
34 |
35 | def test_expose_the_requested_manager_on_show
36 | Store.expects(:find).with('37').returns(mock_store)
37 | mock_store.expects(:manager).returns(mock_manager)
38 | get :show, params: { store_id: '37' }
39 |
40 | assert_equal mock_store, assigns(:store)
41 | assert_equal mock_manager, assigns(:manager)
42 | end
43 |
44 | def test_expose_a_new_manager_on_new
45 | Store.expects(:find).with('37').returns(mock_store)
46 | mock_store.expects(:build_manager).returns(mock_manager)
47 | get :new, params: { store_id: '37' }
48 |
49 | assert_equal mock_store, assigns(:store)
50 | assert_equal mock_manager, assigns(:manager)
51 | end
52 |
53 | def test_expose_the_requested_manager_on_edit
54 | Store.expects(:find).with('37').returns(mock_store)
55 | mock_store.expects(:manager).returns(mock_manager)
56 | get :edit, params: { store_id: '37' }
57 |
58 | assert_equal mock_store, assigns(:store)
59 | assert_equal mock_manager, assigns(:manager)
60 | assert_response :success
61 | end
62 |
63 | def test_expose_a_newly_create_manager_on_create
64 | Store.expects(:find).with('37').returns(mock_store)
65 | mock_store.expects(:build_manager).with(build_parameters({'these' => 'params'})).returns(mock_manager(save: true))
66 | post :create, params: { store_id: '37', manager: {these: 'params'} }
67 |
68 | assert_equal mock_store, assigns(:store)
69 | assert_equal mock_manager, assigns(:manager)
70 | end
71 |
72 | def test_update_the_requested_object_on_update
73 | Store.expects(:find).with('37').returns(mock_store(manager: mock_manager))
74 | mock_manager.expects(:update).with(build_parameters({'these' => 'params'})).returns(true)
75 | put :update, params: { store_id: '37', manager: {these: 'params'} }
76 |
77 | assert_equal mock_store, assigns(:store)
78 | assert_equal mock_manager, assigns(:manager)
79 | end
80 |
81 | def test_the_requested_manager_is_destroyed_on_destroy
82 | Store.expects(:find).with('37').returns(mock_store)
83 | mock_store.expects(:manager).returns(mock_manager)
84 | @controller.expects(:parent_url).returns('http://test.host/')
85 | mock_manager.expects(:destroy)
86 | delete :destroy, params: { store_id: '37' }
87 |
88 | assert_equal mock_store, assigns(:store)
89 | assert_equal mock_manager, assigns(:manager)
90 | end
91 |
92 | protected
93 |
94 | def mock_store(stubs={})
95 | @mock_store ||= mock(stubs)
96 | end
97 |
98 | def mock_manager(stubs={})
99 | @mock_manager ||= mock(stubs)
100 | end
101 |
102 | def build_parameters(hash)
103 | ActionController::Parameters.new(hash)
104 | end
105 | end
106 |
--------------------------------------------------------------------------------
/test/strong_parameters_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require 'test_helper'
3 |
4 | class Widget
5 | extend ActiveModel::Naming
6 | include ActiveModel::Conversion
7 | end
8 |
9 | class WidgetsController < InheritedResources::Base
10 | end
11 |
12 | # test usage of `permitted_params`
13 | class StrongParametersTest < ActionController::TestCase
14 | def setup
15 | draw_routes do
16 | resources :widgets
17 | end
18 |
19 | @controller = WidgetsController.new
20 | @controller.stubs(:widget_url).returns("/")
21 | @controller.stubs(:permitted_params).returns(widget: {permitted: 'param'})
22 | class << @controller
23 | private :permitted_params
24 | end
25 | end
26 |
27 | def teardown
28 | clear_routes
29 | end
30 |
31 | def test_permitted_params_from_new # rubocop:disable Minitest/NoAssertions
32 | Widget.expects(:new).with(permitted: 'param')
33 | get :new, params: { widget: { permitted: 'param', prohibited: 'param' } }
34 | end
35 |
36 | def test_permitted_params_from_create # rubocop:disable Minitest/NoAssertions
37 | Widget.expects(:new).with(permitted: 'param').returns(mock(save: true))
38 | post :create, params: { widget: { permitted: 'param', prohibited: 'param' } }
39 | end
40 |
41 | def test_permitted_params_from_update # rubocop:disable Minitest/NoAssertions
42 | mock_widget = mock
43 | mock_widget.stubs(:class).returns(Widget)
44 | mock_widget.expects(:update).with(permitted: 'param')
45 | mock_widget.stubs(:persisted?).returns(true)
46 | mock_widget.stubs(:to_model).returns(mock_widget)
47 | mock_widget.stubs(:model_name).returns(Widget.model_name)
48 | Widget.expects(:find).with('42').returns(mock_widget)
49 | put :update, params: { id: '42', widget: {permitted: 'param', prohibited: 'param'} }
50 | end
51 |
52 | # `permitted_params` has greater priority than `widget_params`
53 | def test_with_permitted_and_resource_methods # rubocop:disable Minitest/NoAssertions
54 | @controller.stubs(:widget_params).returns(permitted: 'another_param')
55 | class << @controller
56 | private :widget_params
57 | end
58 | Widget.expects(:new).with(permitted: 'param')
59 | get :new, params: { widget: { permitted: 'param', prohibited: 'param' } }
60 | end
61 | end
62 |
63 | # test usage of `widget_params`
64 | class StrongParametersWithoutPermittedParamsTest < ActionController::TestCase
65 | def setup
66 | draw_routes do
67 | resources :widgets
68 | end
69 |
70 | @controller = WidgetsController.new
71 | @controller.stubs(:widget_url).returns("/")
72 | @controller.stubs(:widget_params).returns(permitted: 'param')
73 | class << @controller
74 | private :widget_params
75 | end
76 | end
77 |
78 | def teardown
79 | clear_routes
80 | end
81 |
82 | def test_permitted_params_from_new # rubocop:disable Minitest/NoAssertions
83 | Widget.expects(:new).with(permitted: 'param')
84 | get :new, params: { widget: { permitted: 'param', prohibited: 'param' } }
85 | end
86 |
87 | def test_permitted_params_from_create # rubocop:disable Minitest/NoAssertions
88 | Widget.expects(:new).with(permitted: 'param').returns(mock(save: true))
89 | post :create, params: { widget: { permitted: 'param', prohibited: 'param' } }
90 | end
91 |
92 | def test_permitted_params_from_update # rubocop:disable Minitest/NoAssertions
93 | mock_widget = mock
94 | mock_widget.stubs(:class).returns(Widget)
95 | mock_widget.expects(:update).with(permitted: 'param')
96 | mock_widget.stubs(:persisted?).returns(true)
97 | mock_widget.stubs(:to_model).returns(mock_widget)
98 | mock_widget.stubs(:model_name).returns(Widget.model_name)
99 | Widget.expects(:find).with('42').returns(mock_widget)
100 | put :update, params: { id: '42', widget: {permitted: 'param', prohibited: 'param'} }
101 | end
102 | end
103 |
104 | # test usage of `widget_params` integrated with strong parameters (not using stubs)
105 | class StrongParametersIntegrationTest < ActionController::TestCase
106 | def setup
107 | draw_routes do
108 | resources :widgets
109 | end
110 |
111 | @controller = WidgetsController.new
112 | @controller.stubs(:widget_url).returns("/")
113 |
114 | class << @controller
115 | define_method :widget_params do
116 | params.require(:widget).permit(:permitted)
117 | end
118 | private :widget_params
119 | end
120 | end
121 |
122 | def teardown
123 | clear_routes
124 | end
125 |
126 | def test_permitted_empty_params_from_new # rubocop:disable Minitest/NoAssertions
127 | Widget.expects(:new).with({})
128 | get :new, params: {}
129 | end
130 |
131 | def test_permitted_params_from_new # rubocop:disable Minitest/NoAssertions
132 | Widget.expects(:new).with(build_parameters({'permitted' => 'param'}).permit!)
133 | get :new, params: { widget: { permitted: 'param', prohibited: 'param' } }
134 | end
135 |
136 | def test_permitted_params_from_create # rubocop:disable Minitest/NoAssertions
137 | Widget.expects(:new).with(build_parameters({'permitted' => 'param'}).permit!).returns(mock(save: true))
138 | post :create, params: { widget: { permitted: 'param', prohibited: 'param' } }
139 | end
140 |
141 | def test_permitted_params_from_update # rubocop:disable Minitest/NoAssertions
142 | mock_widget = mock
143 | mock_widget.stubs(:class).returns(Widget)
144 | mock_widget.expects(:update).with(build_parameters({'permitted' => 'param'}).permit!)
145 | mock_widget.stubs(:persisted?).returns(true)
146 | mock_widget.stubs(:to_model).returns(mock_widget)
147 | mock_widget.stubs(:model_name).returns(Widget.model_name)
148 | Widget.expects(:find).with('42').returns(mock_widget)
149 | put :update, params: { id: '42', widget: {permitted: 'param', prohibited: 'param'} }
150 | end
151 |
152 | protected
153 |
154 | def build_parameters(hash)
155 | ActionController::Parameters.new(hash)
156 | end
157 | end
158 |
--------------------------------------------------------------------------------
/test/tasks/gemfile_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require "minitest"
3 |
4 | class GemfilesTest < Minitest::Test
5 | def test_gemfile_is_up_to_date
6 | gemfile = ENV["BUNDLE_GEMFILE"] || "Gemfile"
7 | current_lockfile = File.read("#{gemfile}.lock")
8 |
9 | new_lockfile = Bundler.with_original_env do
10 | `bundle lock --print`
11 | end
12 |
13 | msg = "Please update #{gemfile}'s lock file with `BUNDLE_GEMFILE=#{gemfile} bundle install` and commit the result"
14 |
15 | assert_equal current_lockfile, new_lockfile, msg
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/tasks/gemspec_test.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require "minitest"
3 | require "open3"
4 | require "inherited_resources/version"
5 |
6 | class GemspecTest < Minitest::Test
7 | def setup
8 | @build = Open3.capture3("gem build inherited_resources.gemspec")
9 | end
10 |
11 | def teardown
12 | File.delete("inherited_resources-#{InheritedResources::VERSION}.gem")
13 | end
14 |
15 | def test_succeeds
16 | assert_predicate @build[2], :success?
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | if ENV.fetch('COVERAGE', false)
3 | require 'simplecov'
4 | require 'simplecov-cobertura'
5 | SimpleCov.start do
6 | add_filter %r{^/test/}
7 | minimum_coverage 98
8 | maximum_coverage_drop 0.2
9 | formatter SimpleCov::Formatter::CoberturaFormatter
10 | end
11 | end
12 |
13 | require 'rubygems'
14 | require 'bundler'
15 |
16 | Bundler.setup
17 |
18 | require 'minitest/autorun'
19 | require 'mocha/minitest'
20 | require 'minitest/autorun'
21 | require 'minitest/reporters'
22 |
23 | ENV["RAILS_ENV"] = "test"
24 | RAILS_ROOT = "anywhere"
25 |
26 | require "active_support"
27 | require "active_model"
28 | require "action_controller"
29 |
30 | # TODO: Remove warning gem and the following lines when freerange/mocha#593 will be fixed
31 | require "warning"
32 | Warning.ignore(/Mocha deprecation warning .+ expected keyword arguments .+ but received positional hash/)
33 |
34 | require 'rails-controller-testing'
35 | Rails::Controller::Testing.install
36 |
37 | I18n.load_path << File.join(File.dirname(__FILE__), 'locales', 'en.yml')
38 | I18n.reload!
39 |
40 | class ApplicationController < ActionController::Base; end
41 |
42 | # Add IR to load path and load the main file
43 | $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
44 | require 'inherited_resources'
45 |
46 | ActionController::Base.view_paths = File.join(File.dirname(__FILE__), 'views')
47 |
48 | InheritedResources::Routes = ActionDispatch::Routing::RouteSet.new
49 |
50 | def draw_routes(&block)
51 | InheritedResources::Routes.draw(&block)
52 | end
53 |
54 | def clear_routes
55 | InheritedResources::Routes.draw { }
56 | end
57 |
58 | ActionController::Base.send :include, InheritedResources::Routes.url_helpers
59 |
60 | # Add app base to load path
61 | $:.unshift File.expand_path(File.dirname(__FILE__) + '/../app/controllers')
62 | require 'inherited_resources/base'
63 |
64 | class ActiveSupport::TestCase
65 | setup do
66 | @routes = InheritedResources::Routes
67 | end
68 | end
69 |
--------------------------------------------------------------------------------
/test/views/address/edit.html.erb:
--------------------------------------------------------------------------------
1 | edit html
2 |
--------------------------------------------------------------------------------
/test/views/address/new.html.erb:
--------------------------------------------------------------------------------
1 | new html
2 |
--------------------------------------------------------------------------------
/test/views/address/show.html.erb:
--------------------------------------------------------------------------------
1 | show html
2 |
--------------------------------------------------------------------------------
/test/views/cars/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/cars/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/cars/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/cars/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/cities/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/cities/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/cities/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/cities/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/comments/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/comments/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/comments/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/comments/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/educations/new.html.erb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/activeadmin/inherited_resources/866d9fb29ef22826f608b8226302744ee5a6db3a/test/views/educations/new.html.erb
--------------------------------------------------------------------------------
/test/views/employees/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/employees/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/employees/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/employees/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/geolocation/show.html.erb:
--------------------------------------------------------------------------------
1 | show html
2 |
--------------------------------------------------------------------------------
/test/views/groups/edit.html.erb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/activeadmin/inherited_resources/866d9fb29ef22826f608b8226302744ee5a6db3a/test/views/groups/edit.html.erb
--------------------------------------------------------------------------------
/test/views/managers/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/managers/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/managers/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/painters/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/painters/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/painters/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/painters/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/pets/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/pets/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/pets/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/pets/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/photos/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/plates/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/plates/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/plates/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/plates/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/products/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/products/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/products/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/products/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/professors/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/professors/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/professors/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/professors/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/projects/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
--------------------------------------------------------------------------------
/test/views/projects/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/projects/index.json.erb:
--------------------------------------------------------------------------------
1 | Index JSON
2 |
--------------------------------------------------------------------------------
/test/views/projects/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
--------------------------------------------------------------------------------
/test/views/projects/respond_to_skip_default_template.html.erb:
--------------------------------------------------------------------------------
1 | DefaultTemplate HTML
2 |
--------------------------------------------------------------------------------
/test/views/projects/respond_with_resource.html.erb:
--------------------------------------------------------------------------------
1 | RespondTo HTML
2 |
--------------------------------------------------------------------------------
/test/views/projects/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
--------------------------------------------------------------------------------
/test/views/students/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/students/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/tags/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/tags/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/tags/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/tags/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/trees/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/trees/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/trees/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/trees/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/university/lecturers/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/university/lecturers/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/university/lecturers/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/university/lecturers/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/users/create.js.erb:
--------------------------------------------------------------------------------
1 | Create JS
--------------------------------------------------------------------------------
/test/views/users/destroy.js.erb:
--------------------------------------------------------------------------------
1 | Destroy JS
--------------------------------------------------------------------------------
/test/views/users/edit.html.erb:
--------------------------------------------------------------------------------
1 | Edit HTML
2 |
--------------------------------------------------------------------------------
/test/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 | Index HTML
2 |
--------------------------------------------------------------------------------
/test/views/users/new.html.erb:
--------------------------------------------------------------------------------
1 | New HTML
2 |
--------------------------------------------------------------------------------
/test/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 | Show HTML
2 |
--------------------------------------------------------------------------------
/test/views/users/update.js.erb:
--------------------------------------------------------------------------------
1 | Update JS
--------------------------------------------------------------------------------
/test/views/venue/show.html.erb:
--------------------------------------------------------------------------------
1 | show html
2 |
--------------------------------------------------------------------------------
/test/views/widgets/new.html.erb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/activeadmin/inherited_resources/866d9fb29ef22826f608b8226302744ee5a6db3a/test/views/widgets/new.html.erb
--------------------------------------------------------------------------------