dynamic_controller 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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