simple_resource_controller 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cb28b4c9ce2a17fae1264f71a4091cd4913ed6fc2aeb727b395c27764ffe0f60
4
+ data.tar.gz: 16aaee6c115b1a59ba7d083290db63693103da35099cf24f17296a4ec133cf4c
5
+ SHA512:
6
+ metadata.gz: 7a845c5c753d2b4a7c14dd38c4b216a72d23a5d8b85bd4a2f7db591e4f9bed28d1b5121a59c61bb93bc17e8388235013d8c77f0045c76e8051f4d064cae328b4
7
+ data.tar.gz: 7c8b9ad5385472b79a5cc96fb09e81858e96a9201382257130e62b388b6812260ea93aee060578b10808e9e69b5432d8ee481a9cc4762ddafd11c95dca91e32d
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ *.gem
12
+ coverage
13
+
14
+ *.sqlite3
15
+ spec/dummy_app/log/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at olegz@jetruby.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development, :test do
4
+ gem 'sqlite3'
5
+ gem 'rails'
6
+ gem 'byebug'
7
+ gem 'pry'
8
+ gem 'responders', '~> 2.0'
9
+ gem 'kaminari'
10
+ gem 'has_scope'
11
+ end
12
+
13
+ group :test do
14
+ gem 'rspec-rails'
15
+ gem 'database_cleaner'
16
+ gem 'simplecov'
17
+ gem 'mutant-rspec'
18
+ end
19
+
20
+ # Specify your gem's dependencies in simple_resource_controller.gemspec
21
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Oleg Zaporozhchenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,409 @@
1
+ # SimpleResourceController
2
+
3
+ The simple_resource_controller gem is a lightweight analog of the good old inherited_resources. The main purpose is to save developers time for writing simple CRUD controllers.
4
+
5
+ **Important! Please remember, that this tool was created to help you and not vice versa. Do not try to fight with it. At the end, it’s just a stupid code of the stupid crud controllers.**
6
+
7
+ The main ideas
8
+ 1. This gem allows you to create CRUD controller with minimum configuration
9
+ 2. You do not need to cover these controllers with any tests because gem already covered well
10
+ 2. It just a simple tool with a set of important configurations. It does not want to be a God tool and cover all your use cases
11
+ 3. After reading this documentation you will get a clear understanding how it works under the hood.
12
+ 4. The best practices guide
13
+
14
+ The last point is the most important. When a tool makes so many “magic” it should provide a best practices guide.
15
+
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'simple_resource_controller'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install simple_resource_controller
32
+
33
+ Require it in your `config/application.rb`
34
+
35
+ ```ruby
36
+ require 'simple_resource_controller'
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ A short example
42
+
43
+ ```ruby
44
+ class AnotherArticlesController < ApplicationController
45
+ resource_actions :crud
46
+ resource_class 'Article'
47
+ paginate_collection 10
48
+
49
+ private
50
+
51
+ def after_save_redirect_path
52
+ admin_articles_path
53
+ end
54
+ alias :after_destroy_redirect_path :after_save_redirect_path
55
+
56
+ def after_save_messages
57
+ { notice: 'Saved!' }
58
+ end
59
+
60
+ def permitted_params
61
+ params.require(:article).permit(:title)
62
+ end
63
+ end
64
+ ```
65
+
66
+ ### Controller configuration
67
+
68
+ The first required configuration is an action name.
69
+
70
+ **Please note! The actions definition are inherited, so be careful with the base classes.**
71
+
72
+ ```ruby
73
+ resource_actions :index, :show, :new, :create
74
+ resource_actions :crud # an alias for all actions
75
+ ```
76
+
77
+ Other settings
78
+
79
+ ```ruby
80
+ resource_class ‘User’
81
+ ```
82
+
83
+ Allow specifying the model class. Will get from controller name by default.
84
+
85
+ ```ruby
86
+ paginate_collection 10
87
+ ```
88
+
89
+ Will use the kaminari gem for pagination. It will add `page(params[:page]).per(params[:per_page] || 10)` to your scopes.
90
+
91
+ Of course, I could make this config more flexible, but it contradicts the gem philosophy. Keep it as simple as possible. Creating controllers with that tool should be simple and new developers should not spend much time trying to understand what all these configs mean.
92
+
93
+ ```ruby
94
+ resource_context :current_user
95
+ ```
96
+
97
+ The last and more complex setting is the `resource_context`. Please avoid it if it isn’t clear to you how it works inside.
98
+
99
+ But before describing it I would like to talk about some issues of the inherited_resources gem. The Inherited resources was one of my favorite gems for a long time. But when my team grows I got that for Rails newcomers is so hard to dive in code written with it. Hard to understand what all these `begin_of_association_chain`, `end_of_association_chain` and the other methods do. How to combine them together and use it properly. At the end it’s just a stupid CRUD controller, developers should not spend much time to figure out how it works. But this is the issue both gems are trying to solve - do not spend any time on simple things.
100
+
101
+ So, let's back to the `resource_context` option. It the most “magic” config, but it has only two possible usages.
102
+
103
+ 1. There is a single parameter. In that case, the method with parameter name be the base and gem will build the relation from the controller name
104
+ 2. There are several parameters. In this case, it also uses the method with parameter name as a base. But there is no any additional magic here. All next params will specify the chain (In the first case it was defined by controller name)
105
+
106
+ It’s hard to get it from the description, but the examples below are pretty clear. Please note, that the commented part is the code generated by the gem.
107
+
108
+ ```ruby
109
+ class ArticlesController < ApplicationController
110
+ resource_actions :index
111
+
112
+ #def index
113
+ #@articles = Article.all
114
+ #end
115
+ end
116
+ ```
117
+ ```ruby
118
+ class ArticlesController < ApplicationController
119
+ resource_actions :index
120
+ resource_context :current_user
121
+
122
+ # current_user - from params
123
+ # .articles - from controller name
124
+ #def index
125
+ #@articles = current_user.articles
126
+ #end
127
+ end
128
+ ```
129
+ ```ruby
130
+ class ArticlesController < ApplicationController
131
+ resource_actions :index
132
+ resource_context :current_user, :articles, :recent
133
+
134
+ # no magic with controller name, explicit chain
135
+ #def index
136
+ #@articles = current_user.articles.recent
137
+ #end
138
+ end
139
+ ```
140
+ ```ruby
141
+ class ArticlesController < ApplicationController
142
+ resource_actions :index
143
+ resource_context :category, :articles
144
+
145
+ #def index
146
+ #@articles = category.articles
147
+ #end
148
+
149
+ private
150
+
151
+ def category
152
+ current_user.categories.find(params[:category_id])
153
+ end
154
+ end
155
+ ```
156
+
157
+ If the method doesn’t exist it could try to generate it by supposing that this is a case of the nested resources.
158
+
159
+ ```ruby
160
+ class ArticlesController < ApplicationController
161
+ resource_actions :index
162
+ resource_context :category, :articles
163
+
164
+ #def index
165
+ #@articles = Category.find(params[:category_id]).articles
166
+ #end
167
+ end
168
+ ```
169
+
170
+ The last example details
171
+
172
+ ```ruby
173
+ class ArticlesController < ApplicationController
174
+ resource_actions :index
175
+ resource_context :category, :articles
176
+ #def index
177
+ #@articles = Category.find(params[:category_id]).articles
178
+ #end
179
+ end
180
+ ```
181
+
182
+ Because the `ArticlesController` doesn’t define a `def category; end` method gem will try to build the class name and find the record by `params[:category_id]`
183
+ `
184
+
185
+ The has_scope gem also will automatically work if any scopes specified.
186
+
187
+ ```ruby
188
+ class ArticlesController < ApplicationController
189
+ resource_actions :index
190
+ resource_context :category, :articles
191
+ paginage_collection 10
192
+ has_scope :recent, type: :boolean
193
+ #def index
194
+ #@articles = apply_scopes(Category.find(params[:category_id]).articles).page(params[:page]).per(params[:per_page] || per_page)
195
+ #end
196
+ end
197
+ ```
198
+
199
+ That's all. There are no other available settings. Really simple, isn’t it?
200
+
201
+ ### The template methods
202
+
203
+ Gem was developed with the Template pattern, so there are a few methods you can override your needs.
204
+
205
+ #### The required overrides.
206
+
207
+ You need to define next methods only if you use related actions
208
+ ```ruby
209
+ def after_save_redirect_path
210
+ raise 'Not Implemented'
211
+ end
212
+
213
+ def after_destroy_redirect_path
214
+ raise 'Not Implemented'
215
+ end
216
+
217
+ def permitted_params
218
+ raise 'Not Implemented'
219
+ end
220
+ ```
221
+
222
+ #### Flash messages
223
+
224
+ By default there are no any messages
225
+
226
+ ```ruby
227
+ def after_create_messages
228
+ after_save_messages
229
+ end
230
+
231
+ def after_update_messages
232
+ after_save_messages
233
+ end
234
+
235
+ def after_destroy_messages
236
+ nil
237
+ end
238
+
239
+ def after_save_messages
240
+ nil
241
+ end
242
+ ```
243
+
244
+ You can define any of these methods, They should return a Hash with types and messages
245
+
246
+ ```ruby
247
+ def after_destroy_messages
248
+ { success: 'Record was successfully deleted' }
249
+ end
250
+ ```
251
+
252
+ #### Fetch data methods
253
+
254
+ If the `resource_context` is not enough or you find it too complex, just redefine the basic methods `collection` and `resource`. Both already defined as helper methods and could be used inside views. Don’t forget about the memoization.
255
+
256
+ ```ruby
257
+ def resource
258
+ @article ||= Article.find(params[:id])
259
+ end
260
+
261
+ def collection
262
+ @articles ||= Article.all
263
+ end
264
+ ```
265
+
266
+ #### Controller actions
267
+
268
+ Gem based on the responders one, so you can easy redefine the basic methods. It has the same interface as the inherited_resources.
269
+
270
+ ```ruby
271
+ class ArticlesController < ApplicationController
272
+ resource_actions :update
273
+
274
+ def update
275
+ @article = Article.find(params[:id])
276
+ @article.category = Category.find(params[:category_id])
277
+
278
+ update!
279
+ end
280
+ end
281
+ ```
282
+ ```ruby
283
+ class ArticlesController < ApplicationController
284
+ resource_actions :update
285
+
286
+ def update
287
+ update! do |format|
288
+ unless resource.errors.empty? # failure
289
+ format.html { redirect_to project_url(resource) }
290
+ end
291
+ end
292
+ end
293
+ end
294
+ ```
295
+ ```ruby
296
+ class ArticlesController < ApplicationController
297
+ resource_actions :update
298
+
299
+ def update
300
+ update! do |success, failure|
301
+ failure.html { redirect_to project_url(resourcet) }
302
+ end
303
+ end
304
+ end
305
+ ```
306
+
307
+ #### A bit more about flashes and redirects
308
+
309
+ Instead of
310
+
311
+ ```ruby
312
+ class ArticlesController < ApplicationController
313
+ resource_actions :create
314
+ private
315
+ def after_create_messages
316
+ {notice: ‘Some message’}
317
+ end
318
+ end
319
+ ```
320
+
321
+ You can write
322
+
323
+ ```ruby
324
+ class ArticlesController < ApplicationController
325
+
326
+ resource_actions :create
327
+
328
+ def create
329
+ create! notice: ‘Some message’
330
+ end
331
+ end
332
+ ```
333
+
334
+ The second example looks more elegant, but it’s much easy to write tests for the first one. Because for the first example you just need to ensure that the `after_create_messages` return a correct hash. But for the second one, you will need to write a test for the `create` method from scratch because you redefine it and can’t rely on the gem tests.
335
+
336
+ ### Possible issues
337
+
338
+ I’ve used a contract development to raise exceptions if something configured wrong. Please check the exceptions below you can get.
339
+
340
+ #### `Not Implemented`
341
+
342
+ You didn’t define the template methods. Please check the documentation above.
343
+
344
+ #### `Messages should be specified with Hash`
345
+
346
+ Flash messages should be configured as a hash
347
+
348
+ #### `Please install Kaminari`
349
+
350
+ You are trying to use pagination but gem kaminary is missing
351
+
352
+ #### `#{context} hasn't relation #{scope}`
353
+
354
+ Wrong usage of the `resource_context`. Please remember that there is only single parameter it will build the second one from the controller name
355
+
356
+ ```ruby
357
+ class ArticlesController < ApplicationController
358
+ resource_actions :index
359
+ resource_context :current_user
360
+
361
+ #def index
362
+ #@articles = current_user.articles
363
+ #end
364
+ end
365
+ ```
366
+
367
+ So, the User model should have `has_many : articles` relation
368
+
369
+ #### `Undefined context method #{context_method}`
370
+
371
+ Wrong usage of the `resource_context`. If there is no method with the same name or relevant param - it will cause that exception. Please check the documentation about `resource_context`
372
+
373
+ #### `Could not find model #{class_name} by param #{context_method}_id`
374
+
375
+ The similar exception to the previous one, but in that case, there is a relevant parameter, but there is no a Rails model with relevant name.
376
+
377
+ ```ruby
378
+ class ArticlesController < ApplicationController
379
+ resource_actions :index
380
+ resource_context :category, :articles
381
+
382
+ #def index
383
+ #@articles = Category.find(params[:category_id]).articles
384
+ #end
385
+ end
386
+ ```
387
+
388
+ You will get this exception if the Category model is missing.
389
+
390
+
391
+ #### ```Too many Rails magic. Please check your code```
392
+
393
+ This is my favorite one. The `responders` gem follows the next logic - if a record is valid it means that it was saved to the database. But there is a case when too many Rails magic can cause valid records which weren’t saved to the DB. Yeah, sometimes Rails hurts =)
394
+ If you will get this exception - check your ActiveRecord callbacks, your code has some smells.
395
+
396
+
397
+ ## Contributing
398
+
399
+ Bug reports and pull requests are welcome on GitHub at https://github.com/c3gdlk/simple_resource_controller. This project is intended to be a safe, welcoming space for collaboration.
400
+
401
+ Not work for now =((
402
+ ```
403
+ bundle exec mutant --include lib --require simple_resource_controller --use rspec "SimpleResourceController*"
404
+ ```
405
+
406
+
407
+ ## License
408
+
409
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "simple_resource_controller"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,7 @@
1
+ module SimpleResourceController
2
+ module Configurator
3
+ def resource_actions(*args)
4
+ SimpleResourceController::Controller::ActionsBuilder.build self, args
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,303 @@
1
+ module SimpleResourceController
2
+ module Controller
3
+ module Index
4
+ def index(options={}, &block)
5
+ respond_with collection, options, &block
6
+ end
7
+ alias :index! :index
8
+ end
9
+
10
+ module Show
11
+ def show(options={}, &block)
12
+ respond_with resource, options, &block
13
+ end
14
+ alias :show! :show
15
+ end
16
+
17
+ module New
18
+ def new(options={}, &block)
19
+ build_resource
20
+ respond_with resource, options, &block
21
+ end
22
+ alias :new! :new
23
+ end
24
+
25
+ module Create
26
+ def create(options={}, &block)
27
+ build_resource
28
+ success = save_resource_and_respond!(options, &block)
29
+ ensure
30
+ setup_flash_messages(after_create_messages) if success
31
+ end
32
+ alias :create! :create
33
+ end
34
+
35
+ module Edit
36
+ def edit(options={}, &block)
37
+ respond_with resource, options, &block
38
+ end
39
+ alias :edit! :edit
40
+ end
41
+
42
+ module Update
43
+ def update(options={}, &block)
44
+ success = save_resource_and_respond!(options, &block)
45
+ ensure
46
+ setup_flash_messages(after_update_messages) if success
47
+ end
48
+ alias :update! :update
49
+ end
50
+
51
+ module Destroy
52
+ def destroy(options={}, &block)
53
+ destroy_resource_and_respond!(options, &block)
54
+ ensure
55
+ setup_flash_messages(after_destroy_messages)
56
+ end
57
+ alias :destroy! :destroy
58
+ end
59
+
60
+ module CommonMethods
61
+ private
62
+
63
+ def collection
64
+ return instance_variable_get(:"@#{collection_name}") if instance_variable_get(:"@#{collection_name}").present?
65
+ instance_variable_set(:"@#{collection_name}", apply_scopes_and_pagination(association_chain))
66
+ end
67
+
68
+ def apply_scopes_and_pagination(chain)
69
+ if respond_to?(:apply_scopes, true)
70
+ chain = apply_scopes(chain)
71
+ end
72
+
73
+ per_page = self.class.paginate_collection_config
74
+
75
+ if per_page.present?
76
+ raise 'Please install Kaminari' unless defined?(Kaminari)
77
+
78
+ chain = chain.page(params[:page]).per(params[:per_page] || per_page)
79
+ else
80
+ chain = chain.all
81
+ end
82
+
83
+ chain
84
+ end
85
+
86
+ def collection_name
87
+ resource_name.pluralize
88
+ end
89
+
90
+ def resource_class_name
91
+ self.class.resource_class_config || self.class.name.split('::').last.gsub('Controller', '').singularize
92
+ end
93
+
94
+ def resource_class
95
+ resource_class_name.constantize
96
+ end
97
+
98
+ def resource_name
99
+ resource_class_name.underscore
100
+ end
101
+
102
+ def resource_relation_name
103
+ resource_class_name.underscore.pluralize
104
+ end
105
+
106
+ def association_chain
107
+ self.class.resource_context_config.present? ? association_chain_by_context : resource_class
108
+ end
109
+
110
+ def association_chain_by_context
111
+ specified_scopes.reduce(default_context) do |context, scope|
112
+ raise "#{context.inspect} hasn't relation #{scope}" unless context.respond_to? scope
113
+
114
+ context.public_send(scope)
115
+ end
116
+ end
117
+
118
+ def default_context
119
+ context_method = self.class.resource_context_config.first
120
+
121
+ if self.respond_to? context_method, true
122
+ context = send(context_method)
123
+ elsif params["#{context_method}_id"].present?
124
+ class_name = context_method.to_s.classify
125
+ context_class = class_name.safe_constantize
126
+
127
+ if context_class.present?
128
+ context = context_class.find(params["#{context_method}_id"])
129
+ else
130
+ raise "Could not find model #{class_name} by param #{context_method}_id"
131
+ end
132
+ else
133
+ raise "Undefined context method #{context_method}"
134
+ end
135
+
136
+ context
137
+ end
138
+
139
+ def specified_scopes
140
+ if self.class.resource_context_config.size > 1
141
+ self.class.resource_context_config[1..-1]
142
+ else
143
+ [resource_relation_name.to_sym]
144
+ end
145
+ end
146
+
147
+ def build_resource
148
+ return instance_variable_get(:"@#{resource_name}") if instance_variable_get(:"@#{resource_name}").present?
149
+
150
+ new_instance = association_chain.is_a?(ActiveRecord::Relation) ? association_chain.build : association_chain.new
151
+ instance_variable_set(:"@#{resource_name}", new_instance)
152
+ end
153
+
154
+ def resource
155
+ return instance_variable_get(:"@#{resource_name}") if instance_variable_get(:"@#{resource_name}").present?
156
+ instance_variable_set(:"@#{resource_name}", association_chain.find(params[:id]))
157
+ end
158
+
159
+ def destroy_resource_and_respond!(options={}, &block)
160
+ resource.destroy
161
+
162
+ unless block_given? || options[:location].present?
163
+ options[:location] = after_destroy_redirect_path
164
+ end
165
+
166
+ respond_with resource, options, &block
167
+ end
168
+
169
+ def save_resource_and_respond!(options={}, &block)
170
+ result = resource.update(permitted_params)
171
+
172
+ # process not saved result because of failed callback or another ActiveRecord magic
173
+ if resource.valid? && !result.present?
174
+ resource.errors[:base] << resource_wasnt_saved_message
175
+ end
176
+
177
+ unless block_given? || options[:location].present?
178
+ options[:location] = after_save_redirect_path
179
+ end
180
+
181
+ respond_with resource, options, &block
182
+
183
+ result
184
+ end
185
+
186
+ def resource_wasnt_saved_message
187
+ raise 'Too many Rails magic. Please check your code'
188
+ end
189
+
190
+ def after_create_messages
191
+ after_save_messages
192
+ end
193
+
194
+ def after_update_messages
195
+ after_save_messages
196
+ end
197
+
198
+ def after_destroy_messages
199
+ nil
200
+ end
201
+
202
+ def after_save_messages
203
+ nil
204
+ end
205
+
206
+ def setup_flash_messages(messages)
207
+ return unless messages.present?
208
+
209
+ raise 'Messages should be specified with Hash' unless messages.is_a?(Hash)
210
+
211
+ messages.each do |key, message|
212
+ flash[key] = message
213
+ end
214
+ end
215
+
216
+ # :nocov:
217
+ def after_save_redirect_path
218
+ raise 'Not Implemented'
219
+ end
220
+ # :nocov:
221
+
222
+ # :nocov:
223
+ def after_destroy_redirect_path
224
+ raise 'Not Implemented'
225
+ end
226
+ # :nocov:
227
+
228
+ # :nocov:
229
+ def permitted_params
230
+ raise 'Not Implemented'
231
+ end
232
+ # :nocov:
233
+ end
234
+
235
+ module Accessors
236
+ def resource_class_config
237
+ @resource_class_config
238
+ end
239
+
240
+ def resource_class(value)
241
+ @resource_class_config = value
242
+ end
243
+
244
+ def resource_context_config
245
+ @resource_context_config
246
+ end
247
+
248
+ def resource_context(*values)
249
+ @resource_context_config = values
250
+ end
251
+
252
+ def paginate_collection_config
253
+ @paginate_collection_config
254
+ end
255
+
256
+ def paginate_collection(value)
257
+ @paginate_collection_config = value
258
+ end
259
+ end
260
+
261
+ class ActionsBuilder
262
+ DEPENDENCIES_MAP = {
263
+ index: Index,
264
+ show: Show,
265
+ new: New,
266
+ create: Create,
267
+ edit: Edit,
268
+ update: Update,
269
+ destroy: Destroy
270
+ }.freeze
271
+
272
+ HELPER_METHODS = [:resource, :collection].freeze
273
+
274
+ ALL_ACTIONS_ALIAS = :crud
275
+
276
+ def self.build(controller_class, actions)
277
+ unless actions.include?(ALL_ACTIONS_ALIAS)
278
+ raise 'Unknown action name' unless (actions - DEPENDENCIES_MAP.keys).size.zero?
279
+ end
280
+
281
+ controller_class.extend Accessors
282
+
283
+ loaded_modules = [CommonMethods]
284
+
285
+ if actions.include?(ALL_ACTIONS_ALIAS)
286
+ loaded_modules += DEPENDENCIES_MAP.values
287
+ else
288
+ loaded_modules += actions.map { |action_name| DEPENDENCIES_MAP[action_name] }
289
+ end
290
+
291
+ loaded_modules.uniq.each do |loaded_module|
292
+ controller_class.include loaded_module
293
+ end
294
+
295
+ HELPER_METHODS.each do |method_name|
296
+ controller_class.helper_method method_name
297
+ end
298
+
299
+ controller_class.respond_to :html
300
+ end
301
+ end
302
+ end
303
+ end
@@ -0,0 +1,19 @@
1
+ module SimpleResourceController
2
+ require 'rails'
3
+
4
+ class Railtie < Rails::Railtie
5
+ initializer 'insert SimpleResourceController to ActionController' do
6
+ ActiveSupport.on_load :action_controller do
7
+ SimpleResourceController::Railtie.insert
8
+ end
9
+ end
10
+ end
11
+
12
+ class Railtie
13
+ def self.insert
14
+ if defined?(::ActionController)
15
+ ::ActionController::Base.extend(Configurator)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleResourceController
2
+ VERSION = "0.1.4"
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'simple_resource_controller/version'
2
+ require 'simple_resource_controller/controller'
3
+ require 'simple_resource_controller/configurator'
4
+ require 'simple_resource_controller/railtie'
5
+
6
+ module SimpleResourceController
7
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simple_resource_controller/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "simple_resource_controller"
8
+ spec.version = SimpleResourceController::VERSION
9
+ spec.authors = ["Oleg Zaporozhchenko"]
10
+ spec.email = ["c3.gdlk@gmail.com"]
11
+
12
+ spec.summary = "Simple gem for resource controllers"
13
+ spec.description = "This gem allows to write explicit resource controllers"
14
+ spec.homepage = "https://github.com/c3gdlk/simple_resource_controller"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|coverage)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+
26
+ spec.add_dependency "railties", ">= 3.2"
27
+ spec.add_dependency "actionpack", ">= 3.2"
28
+ spec.add_dependency "responders", "~> 2.0"
29
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_resource_controller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Oleg Zaporozhchenko
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-06-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: railties
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: actionpack
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '3.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: responders
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
97
+ description: This gem allows to write explicit resource controllers
98
+ email:
99
+ - c3.gdlk@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - CODE_OF_CONDUCT.md
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - lib/simple_resource_controller.rb
115
+ - lib/simple_resource_controller/configurator.rb
116
+ - lib/simple_resource_controller/controller.rb
117
+ - lib/simple_resource_controller/railtie.rb
118
+ - lib/simple_resource_controller/version.rb
119
+ - simple_resource_controller.gemspec
120
+ homepage: https://github.com/c3gdlk/simple_resource_controller
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.0.4
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Simple gem for resource controllers
143
+ test_files: []