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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +43 -0
- data/Rakefile +1 -0
- data/dynamic_controller.gemspec +26 -0
- data/lib/dynamic_controller.rb +180 -0
- data/lib/dynamic_controller/version.rb +3 -0
- data/spec/controllers/crud_actions_html_spec.rb +112 -0
- data/spec/controllers/crud_actions_json_spec.rb +92 -0
- data/spec/controllers/nested_crud_actions_html_spec.rb +125 -0
- data/spec/controllers/nested_crud_actions_json_spec.rb +98 -0
- data/spec/dummy/.gitignore +15 -0
- data/spec/dummy/Gemfile +13 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/images/rails.png +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/scaffolds.css.scss +69 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/cities_controller.rb +94 -0
- data/spec/dummy/app/controllers/countries_controller.rb +86 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/city.rb +5 -0
- data/spec/dummy/app/models/country.rb +5 -0
- data/spec/dummy/app/views/cities/_form.html.erb +25 -0
- data/spec/dummy/app/views/cities/edit.html.erb +6 -0
- data/spec/dummy/app/views/cities/index.html.erb +25 -0
- data/spec/dummy/app/views/cities/new.html.erb +5 -0
- data/spec/dummy/app/views/cities/show.html.erb +15 -0
- data/spec/dummy/app/views/countries/_form.html.erb +21 -0
- data/spec/dummy/app/views/countries/edit.html.erb +6 -0
- data/spec/dummy/app/views/countries/index.html.erb +23 -0
- data/spec/dummy/app/views/countries/new.html.erb +5 -0
- data/spec/dummy/app/views/countries/show.html.erb +10 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +62 -0
- data/spec/dummy/config/boot.rb +6 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/db/migrate/20120907174827_create_countries.rb +9 -0
- data/spec/dummy/db/migrate/20120907230842_create_cities.rb +11 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/doc/README_FOR_APP +2 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/tasks/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/index.html +241 -0
- data/spec/dummy/public/robots.txt +5 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/dummy/vendor/plugins/.gitkeep +0 -0
- data/spec/factories.rb +12 -0
- data/spec/spec_helper.rb +34 -0
- metadata +185 -0
data/Gemfile
ADDED
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,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
|