dynamic_controller 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +4 -0
  3. data/README.md +43 -0
  4. data/Rakefile +1 -0
  5. data/dynamic_controller.gemspec +26 -0
  6. data/lib/dynamic_controller.rb +180 -0
  7. data/lib/dynamic_controller/version.rb +3 -0
  8. data/spec/controllers/crud_actions_html_spec.rb +112 -0
  9. data/spec/controllers/crud_actions_json_spec.rb +92 -0
  10. data/spec/controllers/nested_crud_actions_html_spec.rb +125 -0
  11. data/spec/controllers/nested_crud_actions_json_spec.rb +98 -0
  12. data/spec/dummy/.gitignore +15 -0
  13. data/spec/dummy/Gemfile +13 -0
  14. data/spec/dummy/README.rdoc +261 -0
  15. data/spec/dummy/Rakefile +7 -0
  16. data/spec/dummy/app/assets/images/rails.png +0 -0
  17. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  18. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  19. data/spec/dummy/app/assets/stylesheets/scaffolds.css.scss +69 -0
  20. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  21. data/spec/dummy/app/controllers/cities_controller.rb +94 -0
  22. data/spec/dummy/app/controllers/countries_controller.rb +86 -0
  23. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  24. data/spec/dummy/app/mailers/.gitkeep +0 -0
  25. data/spec/dummy/app/models/.gitkeep +0 -0
  26. data/spec/dummy/app/models/city.rb +5 -0
  27. data/spec/dummy/app/models/country.rb +5 -0
  28. data/spec/dummy/app/views/cities/_form.html.erb +25 -0
  29. data/spec/dummy/app/views/cities/edit.html.erb +6 -0
  30. data/spec/dummy/app/views/cities/index.html.erb +25 -0
  31. data/spec/dummy/app/views/cities/new.html.erb +5 -0
  32. data/spec/dummy/app/views/cities/show.html.erb +15 -0
  33. data/spec/dummy/app/views/countries/_form.html.erb +21 -0
  34. data/spec/dummy/app/views/countries/edit.html.erb +6 -0
  35. data/spec/dummy/app/views/countries/index.html.erb +23 -0
  36. data/spec/dummy/app/views/countries/new.html.erb +5 -0
  37. data/spec/dummy/app/views/countries/show.html.erb +10 -0
  38. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  39. data/spec/dummy/config.ru +4 -0
  40. data/spec/dummy/config/application.rb +62 -0
  41. data/spec/dummy/config/boot.rb +6 -0
  42. data/spec/dummy/config/database.yml +25 -0
  43. data/spec/dummy/config/environment.rb +5 -0
  44. data/spec/dummy/config/environments/development.rb +37 -0
  45. data/spec/dummy/config/environments/production.rb +67 -0
  46. data/spec/dummy/config/environments/test.rb +37 -0
  47. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/spec/dummy/config/initializers/inflections.rb +15 -0
  49. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  50. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  51. data/spec/dummy/config/initializers/session_store.rb +8 -0
  52. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  53. data/spec/dummy/config/locales/en.yml +5 -0
  54. data/spec/dummy/config/routes.rb +5 -0
  55. data/spec/dummy/db/migrate/20120907174827_create_countries.rb +9 -0
  56. data/spec/dummy/db/migrate/20120907230842_create_cities.rb +11 -0
  57. data/spec/dummy/db/schema.rb +31 -0
  58. data/spec/dummy/db/seeds.rb +7 -0
  59. data/spec/dummy/doc/README_FOR_APP +2 -0
  60. data/spec/dummy/lib/assets/.gitkeep +0 -0
  61. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  62. data/spec/dummy/log/.gitkeep +0 -0
  63. data/spec/dummy/public/404.html +26 -0
  64. data/spec/dummy/public/422.html +26 -0
  65. data/spec/dummy/public/500.html +25 -0
  66. data/spec/dummy/public/favicon.ico +0 -0
  67. data/spec/dummy/public/index.html +241 -0
  68. data/spec/dummy/public/robots.txt +5 -0
  69. data/spec/dummy/script/rails +6 -0
  70. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  71. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  72. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  73. data/spec/factories.rb +12 -0
  74. data/spec/spec_helper.rb +34 -0
  75. metadata +185 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in dynamic_controller.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # DynamicController
2
+
3
+ Simple way to add CRUD actions to Rails controllers.
4
+
5
+ Suppoted formats HTML and JSON.
6
+
7
+ Tested with Ruby 1.9.3 and Rails 3.2.8.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'dynamic_controller'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install dynamic_controller
22
+
23
+ ## Adding CRUD actions to resource controller
24
+
25
+ class UsersController < ApplicationController
26
+ has_crud_actions
27
+ end
28
+
29
+ has_crud_actions adds index, show, new, edit, create, update and destroy actions to controller
30
+
31
+ ## Nested resources support
32
+
33
+ class ProfilesController < ApplicationController
34
+ has_crud_actions nested_of: User
35
+ end
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dynamic_controller/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'dynamic_controller'
7
+ s.version = DynamicController::VERSION
8
+ s.authors = ['Gabriel Naiman']
9
+ s.email = ['gabynaiman@gmail.com']
10
+ s.homepage = 'https://github.com/gabynaiman/dynamic_controller'
11
+ s.summary = 'Simple way to add CRUD actions to Rails controllers'
12
+ s.description = 'Simple way to add CRUD actions to Rails controllers'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency 'ransack'
20
+ s.add_dependency 'kaminari'
21
+
22
+ s.add_development_dependency 'rails'
23
+ s.add_development_dependency 'sqlite3'
24
+ s.add_development_dependency 'rspec-rails'
25
+ s.add_development_dependency 'factory_girl_rails'
26
+ end
@@ -0,0 +1,180 @@
1
+ require 'dynamic_controller/version'
2
+ require 'ransack'
3
+ require 'kaminari'
4
+
5
+ module DynamicController
6
+
7
+ module ClassMethods
8
+
9
+ attr_reader :dynamic_options
10
+
11
+ def has_crud_actions(options={})
12
+ send :include, CrudActions
13
+ before_filter :load_nested if options[:nested_of]
14
+ @dynamic_options = options
15
+ end
16
+
17
+ end
18
+
19
+ module CrudActions
20
+
21
+ def self.included(base)
22
+ base.helper_method [:resource_class, :controller_namespace]
23
+ base.respond_to :html, :json
24
+ base.rescue_from StandardError, with: :handle_error
25
+ end
26
+
27
+ def index
28
+ if parent_model
29
+ self.collection = parent_model.send(controller_name).search(params[:q]).result.page(params[:page])
30
+ else
31
+ self.collection = resource_class.search(params[:q]).result.page(params[:page])
32
+ end
33
+
34
+ respond_with collection
35
+ end
36
+
37
+ def show
38
+ if parent_model
39
+ self.model = parent_model.send(controller_name).find(params[:id])
40
+ else
41
+ self.model = resource_class.find(params[:id])
42
+ end
43
+
44
+ respond_with model
45
+ end
46
+
47
+ def new
48
+ if parent_model
49
+ self.model = parent_model.send(controller_name).build
50
+ else
51
+ self.model = resource_class.new
52
+ end
53
+ end
54
+
55
+ def edit
56
+ if parent_model
57
+ self.model = parent_model.send(controller_name).find(params[:id])
58
+ else
59
+ self.model = resource_class.find(params[:id])
60
+ end
61
+ end
62
+
63
+ def create
64
+ if parent_model
65
+ self.model = parent_model.send(controller_name).build(params[resource_class.model_name.underscore])
66
+ else
67
+ self.model = resource_class.new(params[resource_class.model_name.underscore])
68
+ end
69
+
70
+ if model.save
71
+ flash_message = "#{resource_class.model_name.human} successfully created"
72
+ if params[:save_and_new]
73
+ flash[:success] = flash_message
74
+ redirect_to action: :new
75
+ else
76
+ flash.now[:success] = flash_message
77
+ respond_to do |format|
78
+ format.html { redirect_to url_for([parent_model, model].compact) }
79
+ format.json { render json: model, status: :created }
80
+ end
81
+ end
82
+ else
83
+ respond_to do |format|
84
+ format.html { render :new }
85
+ format.json { render json: model.errors, status: :unprocessable_entity }
86
+ end
87
+ end
88
+ end
89
+
90
+ def update
91
+ if parent_model
92
+ self.model = parent_model.send(controller_name).find(params[:id])
93
+ else
94
+ self.model = resource_class.find(params[:id])
95
+ end
96
+
97
+ if model.update_attributes(params[resource_class.model_name.underscore])
98
+ flash.now[:success] = "#{resource_class.model_name.human} successfully updated"
99
+ respond_to do |format|
100
+ format.html { redirect_to url_for([parent_model, model].compact) }
101
+ format.json { head :no_content }
102
+ end
103
+ else
104
+ respond_to do |format|
105
+ format.html { render :edit }
106
+ format.json { render json: model.errors, status: :unprocessable_entity }
107
+ end
108
+ end
109
+ end
110
+
111
+ def destroy
112
+ if parent_model
113
+ self.model = parent_model.send(controller_name).find(params[:id])
114
+ else
115
+ self.model = resource_class.find(params[:id])
116
+ end
117
+
118
+ if model.destroy
119
+ flash[:warning] = "#{resource_class.model_name.human} successfully removed"
120
+ respond_to do |format|
121
+ format.html { redirect_to action: :index }
122
+ format.json { head :no_content }
123
+ end
124
+ else
125
+ flash[:danger] = "#{resource_class.model_name.human} could not be deleted"
126
+ respond_to do |format|
127
+ format.html { redirect_to action: :index }
128
+ format.json { render json: model.errors, status: :unprocessable_entity }
129
+ end
130
+ end
131
+ end
132
+
133
+ def resource_class
134
+ @resource_class ||= controller_name.classify.constantize
135
+ end
136
+
137
+ def controller_namespace
138
+ @controller_namespace ||= self.class.name.split('::')[0..-2].map(&:underscore).join('_') unless self.class.name.split('::')[0..-2].empty?
139
+ end
140
+
141
+ private
142
+
143
+ def collection=(value)
144
+ instance_variable_set("@#{controller_name}", value)
145
+ end
146
+
147
+ def collection
148
+ instance_variable_get("@#{controller_name}")
149
+ end
150
+
151
+ def model=(value)
152
+ instance_variable_set("@#{controller_name.singularize}", value)
153
+ end
154
+
155
+ def model
156
+ instance_variable_get("@#{controller_name.singularize}")
157
+ end
158
+
159
+ def load_nested
160
+ parent_klass = self.class.dynamic_options[:nested_of]
161
+ instance_variable_set("@#{parent_klass.to_s.underscore}", parent_klass.find(params["#{parent_klass.to_s.underscore}_id"]))
162
+ end
163
+
164
+ def parent_model
165
+ instance_variable_get("@#{self.class.dynamic_options[:nested_of].to_s.underscore}")
166
+ end
167
+
168
+ def handle_error(error)
169
+ respond_to do |format|
170
+ format.html { raise error }
171
+ format.json { render json: error.message, status: :internal_server_error }
172
+ end
173
+ end
174
+
175
+ end
176
+
177
+ end
178
+
179
+ ActionController::Base.send :extend, DynamicController::ClassMethods
180
+
@@ -0,0 +1,3 @@
1
+ module DynamicController
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ describe CountriesController, '-> HTML', type: :controller do
4
+
5
+ it 'Index -> GET /resources' do
6
+ 3.times { create :country }
7
+
8
+ get :index
9
+
10
+ response.should be_success
11
+ response.content_type.should eq 'text/html'
12
+ response.should render_template :index
13
+ assigns(:countries).should eq Country.all
14
+ end
15
+
16
+ it 'Show -> GET /resources/:id' do
17
+ country = create :country
18
+
19
+ get :show, id: country.id
20
+
21
+ response.should be_success
22
+ response.content_type.should eq 'text/html'
23
+ response.should render_template :show
24
+ assigns(:country).should eq country
25
+ end
26
+
27
+ it 'New -> GET /resources/new' do
28
+ get :new
29
+
30
+ response.should be_success
31
+ response.content_type.should eq 'text/html'
32
+ response.should render_template :new
33
+ assigns(:country).should be_a Country
34
+ assigns(:country).should be_new_record
35
+ end
36
+
37
+ it 'Edit -> GET /resources/:id/edit' do
38
+ country = create :country
39
+
40
+ get :edit, id: country.id
41
+
42
+ response.should be_success
43
+ response.content_type.should eq 'text/html'
44
+ response.should render_template :edit
45
+ assigns(:country).should eq country
46
+ end
47
+
48
+ context 'Create -> POST /resources' do
49
+
50
+ it 'Successfully' do
51
+ attributes = attributes_for :country
52
+
53
+ post :create, country: attributes
54
+
55
+ response.should be_redirect
56
+ response.content_type.should eq 'text/html'
57
+ response.should redirect_to assigns(:country)
58
+ assigns(:country).id.should_not be_nil
59
+ assigns(:country).name.should eq attributes[:name]
60
+ end
61
+
62
+ it 'With errors' do
63
+ post :create
64
+
65
+ response.should be_success
66
+ response.content_type.should eq 'text/html'
67
+ response.should render_template :new
68
+ assigns(:country).should have(1).errors_on(:name)
69
+ end
70
+
71
+ end
72
+
73
+ context 'Update -> PUT /resources/:id' do
74
+
75
+ it 'Successfully' do
76
+ country = create :country
77
+ attributes = {name: "#{country.name} updated"}
78
+
79
+ put :update, id: country.id, country: attributes
80
+
81
+ response.should be_redirect
82
+ response.content_type.should eq 'text/html'
83
+ response.should redirect_to country
84
+ assigns(:country).name.should eq attributes[:name]
85
+ end
86
+
87
+ it 'With errors' do
88
+ country = create :country
89
+
90
+ put :update, id: country.id, country: {name: nil}
91
+
92
+ response.should be_success
93
+ response.content_type.should eq 'text/html'
94
+ response.should render_template :edit
95
+ assigns(:country).should have(1).errors_on(:name)
96
+ end
97
+
98
+ end
99
+
100
+ it 'Destroy -> DELETE /resources/:id' do
101
+ country = create :country
102
+
103
+ delete :destroy, id: country.id
104
+
105
+ response.should be_redirect
106
+ response.content_type.should eq 'text/html'
107
+ response.should redirect_to countries_path
108
+
109
+ Country.find_by_id(country.id).should be_nil
110
+ end
111
+
112
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ describe CountriesController, '-> JSON', type: :controller do
4
+
5
+ it 'Index -> GET /resources.json' do
6
+ 3.times { create :country }
7
+
8
+ get :index, format: :json
9
+
10
+ response.status.should be 200 # OK
11
+ response.content_type.should eq 'application/json'
12
+ JSON.parse(response.body).each do |attributes|
13
+ attributes['name'].should eq Country.find(attributes['id']).name
14
+ end
15
+ end
16
+
17
+ it 'Show -> GET /resources/:id.json' do
18
+ country = create :country
19
+
20
+ get :show, format: :json, id: country.id
21
+
22
+ response.status.should be 200 # OK
23
+ response.content_type.should eq 'application/json'
24
+ attributes = JSON.parse(response.body)
25
+ attributes['id'].should eq country.id
26
+ attributes['name'].should eq country.name
27
+ end
28
+
29
+ context 'Create -> POST /resources.json' do
30
+
31
+ it 'Successfully' do
32
+ attributes = attributes_for :country
33
+
34
+ post :create, format: :json, country: attributes
35
+
36
+ response.status.should be 201 # Created
37
+ response.content_type.should eq 'application/json'
38
+ country = JSON.parse(response.body)
39
+ country['id'].should_not be_nil
40
+ country['name'].should eq attributes[:name]
41
+
42
+ Country.find_by_id(country['id']).should_not be_nil
43
+ end
44
+
45
+ it 'With errors' do
46
+ post :create, format: :json
47
+
48
+ response.status.should eq 422 # Unprocessable Entity
49
+ response.content_type.should eq 'application/json'
50
+ JSON.parse(response.body).should have_key 'name'
51
+ end
52
+
53
+ end
54
+
55
+ context 'Update -> PUT /resources/:id.json' do
56
+
57
+ it 'Successfully' do
58
+ country = create :country
59
+ attributes = {name: "#{country.name} updated"}
60
+
61
+ put :update, format: :json, id: country.id, country: attributes
62
+
63
+ response.status.should eq 204 # No Content
64
+ response.content_type.should eq 'application/json'
65
+
66
+ Country.find(country.id).name.should eq attributes[:name]
67
+ end
68
+
69
+ it 'With errors' do
70
+ country = create :country
71
+
72
+ put :update, format: :json, id: country.id, country: {name: nil}
73
+
74
+ response.status.should eq 422 # Unprocessable Entity
75
+ response.content_type.should eq 'application/json'
76
+ JSON.parse(response.body).should have_key 'name'
77
+ end
78
+
79
+ end
80
+
81
+ it 'Destroy -> DELETE /resources/:id.json' do
82
+ country = create :country
83
+
84
+ delete :destroy, format: :json, id: country.id
85
+
86
+ response.status.should eq 204 # No Content
87
+ response.content_type.should eq 'application/json'
88
+
89
+ Country.find_by_id(country.id).should be_nil
90
+ end
91
+
92
+ end