abstracted 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.envrc +1 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +14 -0
  7. data/Gemfile.lock +218 -0
  8. data/Guardfile +77 -0
  9. data/MIT-LICENSE +20 -0
  10. data/README.rdoc +3 -0
  11. data/Rakefile +15 -0
  12. data/abstracted.gemspec +51 -0
  13. data/app/assets/images/abstracted/.keep +0 -0
  14. data/app/assets/javascripts/abstract_resources.js +39 -0
  15. data/app/assets/javascripts/abstracted/.keep +0 -0
  16. data/app/assets/javascripts/crud.js.coffee +49 -0
  17. data/app/assets/javascripts/initializers.js.coffee +111 -0
  18. data/app/assets/stylesheets/abstract_resources.css +5 -0
  19. data/app/assets/stylesheets/abstracted/.keep +0 -0
  20. data/app/assets/stylesheets/scaffold.css +56 -0
  21. data/app/controllers/.keep +0 -0
  22. data/app/controllers/abstract_resources_controller.rb +290 -0
  23. data/app/controllers/application_controller.rb +22 -0
  24. data/app/helpers/.keep +0 -0
  25. data/app/helpers/abstract_resources_helper.rb +26 -0
  26. data/app/mailers/.keep +0 -0
  27. data/app/models/.keep +0 -0
  28. data/app/models/abstract_resource.rb +122 -0
  29. data/app/models/concerns/roleable.rb +61 -0
  30. data/app/policies/abstract_resource_policy.rb +58 -0
  31. data/app/views/.keep +0 -0
  32. data/app/views/abstract_resources/_default.html.erb +11 -0
  33. data/app/views/abstract_resources/destroy.js.haml +1 -0
  34. data/app/views/abstract_resources/edit.html.haml +11 -0
  35. data/app/views/abstract_resources/index.html.erb +1 -0
  36. data/app/views/abstract_resources/new.html.haml +12 -0
  37. data/app/views/abstract_resources/show.html.haml +13 -0
  38. data/bin/rails +12 -0
  39. data/config/locales/abstracted.en.yml +20 -0
  40. data/config/routes.rb +4 -0
  41. data/lib/abstracted.rb +8 -0
  42. data/lib/abstracted/engine.rb +19 -0
  43. data/lib/abstracted/version.rb +3 -0
  44. data/lib/abstracted_responder.rb +7 -0
  45. data/lib/tasks/abstracted_tasks.rake +4 -0
  46. data/spec/controllers/abstract_resources_controller_spec.rb +241 -0
  47. data/spec/dummy/README.rdoc +28 -0
  48. data/spec/dummy/Rakefile +6 -0
  49. data/spec/dummy/app/assets/images/.keep +0 -0
  50. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  51. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  52. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  53. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  54. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  55. data/spec/dummy/app/mailers/.keep +0 -0
  56. data/spec/dummy/app/models/.keep +0 -0
  57. data/spec/dummy/app/models/concerns/.keep +0 -0
  58. data/spec/dummy/app/models/user.rb +3 -0
  59. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  60. data/spec/dummy/bin/bundle +3 -0
  61. data/spec/dummy/bin/rails +4 -0
  62. data/spec/dummy/bin/rake +4 -0
  63. data/spec/dummy/bin/setup +29 -0
  64. data/spec/dummy/config.ru +4 -0
  65. data/spec/dummy/config/application.rb +26 -0
  66. data/spec/dummy/config/boot.rb +5 -0
  67. data/spec/dummy/config/database.yml +25 -0
  68. data/spec/dummy/config/environment.rb +5 -0
  69. data/spec/dummy/config/environments/development.rb +41 -0
  70. data/spec/dummy/config/environments/production.rb +79 -0
  71. data/spec/dummy/config/environments/test.rb +42 -0
  72. data/spec/dummy/config/initializers/assets.rb +11 -0
  73. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  75. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  76. data/spec/dummy/config/initializers/inflections.rb +16 -0
  77. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  78. data/spec/dummy/config/initializers/session_store.rb +3 -0
  79. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  80. data/spec/dummy/config/locales/en.yml +23 -0
  81. data/spec/dummy/config/routes.rb +56 -0
  82. data/spec/dummy/config/secrets.yml +22 -0
  83. data/spec/dummy/db/development.sqlite3 +0 -0
  84. data/spec/dummy/db/schema.rb +21 -0
  85. data/spec/dummy/db/test.sqlite3 +0 -0
  86. data/spec/dummy/lib/assets/.keep +0 -0
  87. data/spec/dummy/log/.keep +0 -0
  88. data/spec/dummy/log/development.log +0 -0
  89. data/spec/dummy/log/test.log +6229 -0
  90. data/spec/dummy/public/404.html +67 -0
  91. data/spec/dummy/public/422.html +67 -0
  92. data/spec/dummy/public/500.html +66 -0
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/factories/abstract_resources.rb +6 -0
  95. data/spec/factories/users.rb +5 -0
  96. data/spec/features/posts/manage_posts_spec.rb +24 -0
  97. data/spec/models/abstract_resource_spec.rb +14 -0
  98. data/spec/rails_helper.rb +114 -0
  99. data/spec/spec_helper.rb +97 -0
  100. data/test/integration/abstract_resource_test.rb +7 -0
  101. metadata +424 -0
@@ -0,0 +1,49 @@
1
+ #
2
+ # deletePost handles deleting records
3
+ #
4
+ # dependencies:
5
+ # sweetalert
6
+ #
7
+ # data-url="", data-id="" - eg.
8
+
9
+ closeSweetAlert = () ->
10
+ try
11
+ swal.close()
12
+ catch error
13
+ $('.sweet-overlay').hide()
14
+ $('.sweet-alert').hide()
15
+
16
+ @deletePost = ($elem) ->
17
+ try
18
+ url = $elem.data('url') + "/" + $elem.data('id') + ".js"
19
+ $remove = $($elem.data('remove'))
20
+ request = $.ajax
21
+ url: url,
22
+ type: "delete",
23
+ statusCode:
24
+
25
+ 200: (response,textStatus,jqXHR) ->
26
+ if $remove
27
+ $remove.hide()
28
+ closeSweetAlert()
29
+ $('.message_container').html(response.responseText)
30
+
31
+ 301: () ->
32
+ $elem.show()
33
+ closeSweetAlert()
34
+ swal "Ikke slettet!", "Posten blev ikke slettet - årsagen ikke kendt", "warning"
35
+
36
+ 401: (response) ->
37
+ $('.message_container').append(response.responseText)
38
+ closeSweetAlert()
39
+
40
+ 409: (response) ->
41
+ $('.message_container').append(response.responseText)
42
+ closeSweetAlert()
43
+
44
+ 412: () ->
45
+ closeSweetAlert()
46
+ swal "Øv!", "Et eller andet gik galt!", "error"
47
+
48
+ catch error
49
+ swal "Hmmm", "#{error}", "error"
@@ -0,0 +1,111 @@
1
+ #
2
+ # initializeSweetAlert
3
+ # initializes the sweetalert prompt
4
+ #
5
+ @initializeSweetAlert = () ->
6
+ try
7
+ # console.log 'sweet alert initializing...'
8
+ sweetHTML = '<div class="sweet-overlay" tabIndex="-1"></div><div class="sweet-alert" tabIndex="-1"><div class="icon error"><span class="x-mark"><span class="line left"></span><span class="line right"></span></span></div><div class="icon warning"> <span class="body"></span> <span class="dot"></span> </div> <div class="icon info"></div> <div class="icon success"> <span class="line tip"></span> <span class="line long"></span> <div class="placeholder"></div> <div class="fix"></div> </div> <div class="icon custom"></div> <h2>Title</h2><p>Text</p><button class="cancel" tabIndex="2">Cancel</button><button class="confirm" tabIndex="1">OK</button></div>'
9
+ sweetWrap = document.createElement('div')
10
+ sweetWrap.innerHTML = sweetHTML
11
+ $(document.body).append(sweetWrap)
12
+ catch error
13
+ console.log error
14
+
15
+
16
+ #
17
+ # initializeDeleteLinks
18
+ # initializes the tags classed with '.delete_link' to verify deleting an issue
19
+ #
20
+ @initializeDeleteLinks = () ->
21
+ $('.delete_link').on 'click', (e) ->
22
+ e.preventDefault()
23
+ $elem = $(this)
24
+ $elem.hide()
25
+
26
+ swal
27
+ title: "Er du sikker?",
28
+ text: "Hvis du accepterer slettes posten <b>" + $(this).data('name') + "</b> permanent, og du vil ikke kunne hente den frem igen!",
29
+ type: "warning",
30
+ html: true,
31
+ showCancelButton: true,
32
+ confirmButtonColor: "#DD6B55",
33
+ confirmButtonText: "Ja, slet den!",
34
+ cancelButtonText: "Nej - jeg har fortrudt!"
35
+ closeOnConfirm: false,
36
+ # closeOnCancel: true,
37
+ (confirmed) ->
38
+ if !confirmed
39
+ $elem.show()
40
+ # swal "Ok!", "Posten blev ikke slettet - du valgte at fortryde.", "success"
41
+ else
42
+ deletePost($elem)
43
+
44
+ # console.log( ".delete_link event handler was set")
45
+
46
+
47
+ #
48
+ # fadeItOut will fade an element out with a preset or
49
+ # supplied delay
50
+ #
51
+ @fadeItOut = (e,delay=3500) ->
52
+ $(e).delay( delay ).fadeOut( 1000 )
53
+
54
+
55
+ #
56
+ # PageOnLoad loads and initializes
57
+ # fixed elements like SELECT's, Materialized's elements, et al.
58
+ #
59
+ @pageOnLoad = () ->
60
+
61
+ #
62
+ # Initialize the 'hamburger'
63
+ #
64
+ $(".button-collapse").sideNav();
65
+
66
+ #
67
+ # Initialize collapsible (uncomment the line below if you use the dropdown variation)
68
+ #
69
+ $('.collapsible').collapsible
70
+ accordion : true # A setting that changes the collapsible behavior to expandable instead of the default accordion style
71
+
72
+ #
73
+ # Initialize SELECT's
74
+ #
75
+ $('select').material_select();
76
+
77
+ #
78
+ # Initialize INPUT TYPE='DATE'
79
+ #
80
+ # %input.datepicker{ type:"date" }
81
+ #
82
+ $('.datepicker').pickadate
83
+ selectMonths: true, # Creates a dropdown to control month
84
+ selectYears: 15 # Creates a dropdown of 15 years to control year
85
+
86
+ #
87
+ # Prepare delete_link's for acting on clicks to delete posts
88
+ #
89
+ initializeDeleteLinks()
90
+
91
+ #
92
+ # Try to keep users from double-clicking submit's
93
+ #
94
+ # document.addEventListener('DOMContentLoaded', disableMultipleSubmits, false);
95
+
96
+ #
97
+ # Prepare close-notice's for acting on clicks to remove div
98
+ #
99
+ $('.message_container').delegate 'a.close-notice', 'click', () ->
100
+ $(this).closest('.alert').remove()
101
+
102
+ #
103
+ # make drop-downs react nicely
104
+ #
105
+ $(".dropdown-button").dropdown()
106
+
107
+ # here to test whether pageOnLoad runs - -
108
+ # try
109
+ # swal( 'pageOnLoad', 'pageOnLoad blev kaldt!', 'success')
110
+ # catch
111
+ # console.log 'autch!'
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Place all the styles related to the matching controller here.
3
+ * They will automatically be included in application.css.
4
+ *
5
+ */
@@ -0,0 +1,56 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
File without changes
@@ -0,0 +1,290 @@
1
+ require "abstracted_responder"
2
+
3
+ class AbstractResourcesController < ApplicationController
4
+ self.responder = ::AbstractedResponder
5
+ respond_to :html, :xml, :js, :json
6
+
7
+ before_action :set_resource
8
+ before_action :set_resources, only: [:index]
9
+ before_action :set_variant_template
10
+
11
+ before_filter :authenticate_user!
12
+ after_action :verify_authorized
13
+ # after_action :manage_parenthood, only: [:create,:update,:destroy]
14
+
15
+ # default implementation
16
+ def show
17
+ authorize resource
18
+ respond_with resource
19
+ rescue Exception => e
20
+ scoop_from_error e
21
+ end
22
+
23
+ def new
24
+ resource.parent_id = params[:parent_id] if resource.respond_to? :parent_id
25
+ authorize resource
26
+ respond_with resource
27
+ rescue Exception => e
28
+ scoop_from_error e
29
+ end
30
+
31
+ def edit
32
+ authorize resource
33
+ respond_with resource
34
+ rescue Exception => e
35
+ scoop_from_error e
36
+ end
37
+
38
+ def index
39
+ authorize resource_class
40
+ respond_with resources
41
+ rescue Exception => e
42
+ scoop_from_error e
43
+ end
44
+
45
+ def create
46
+ @resource = resource_class.new(resource_params)
47
+ authorize resource
48
+ flash[:notice] = t('.success.created', resource: resource_class.to_s ) if resource.save
49
+ respond_with(resource)
50
+ rescue Exception => e
51
+ scoop_from_error e
52
+ end
53
+
54
+ def update
55
+ authorize resource
56
+ flash[:notice] = t('.success.updated', resource: resource_class.to_s ) if resource.update_attributes(resource_params)
57
+ respond_with(resource)
58
+ rescue Exception => e
59
+ scoop_from_error e
60
+ end
61
+
62
+ def destroy
63
+ authorize resource
64
+ result = true if resource.destroy
65
+ result ? (flash.now[:notice] = t('.success', resource: resource_class.to_s)) : (flash.now[:error] = t('.deleted.error',resource: resource_class.to_s))
66
+ if result==true
67
+ render layout:false, status: 200, locals: { result: true }
68
+ else
69
+ render layout:false, status: 301, locals: { result: true }
70
+ end
71
+ rescue Exception => e
72
+ scoop_from_error e
73
+ end
74
+
75
+ def resource_params
76
+ raise 'You need to "def resource_params" on the %sController! (see: http://blog.trackets.com/2013/08/17/strong-parameters-by-example.html)' % params[:controller].capitalize
77
+ end
78
+
79
+ def set_resource
80
+ parent
81
+ resource
82
+ end
83
+
84
+ def set_resources
85
+ resources
86
+ end
87
+
88
+ def resource
89
+ @resource ||= (params[:id].nil? ? resource_class.new : resource_class.find(params[:id]) ) rescue nil
90
+ end
91
+
92
+ def resource_name
93
+ resource_class.to_s.underscore.pluralize
94
+ end
95
+
96
+ def resource_class
97
+ @resource_class ||= params[:controller].singularize.classify.constantize rescue nil
98
+ end
99
+
100
+ def parent
101
+ @parent ||= find_parent
102
+ end
103
+
104
+
105
+ def parent_class
106
+ @parent_class ||= @parent.class
107
+ end
108
+
109
+ def parent?
110
+ !(%w{NilClass TrueClass FalseClass}.include? @parent.class.to_s)
111
+ end
112
+
113
+ #
114
+ #
115
+ # return the resources collection - preferably from the cache
116
+ def resources options={}
117
+ @resources ||= find_resources options
118
+ end
119
+
120
+
121
+ #
122
+ # returns the url for the resource - like /users/1
123
+ def resource_url options={}
124
+ options = resource_options(options)
125
+ action= case params[:action]
126
+ when 'show'; '/%s' % resource.id
127
+ when 'edit'; '/%s/edit' % resource.id
128
+ else ''
129
+ end
130
+ parent? ? ("%s/%s%s%s" % [parent_url,resource_name,action,options]) : ("/%s%s%s" % [resource_name,action,options])
131
+ end
132
+
133
+
134
+ #
135
+ # returns the url for the resources - /employees or /employees/1/events
136
+ def resources_url options={}
137
+ options = resource_options(options)
138
+ "%s/%s" % [ parent_url, resource_name ]
139
+ end
140
+
141
+ #
142
+ # parent_url returns the parent url - /employees/1
143
+ def parent_url
144
+ parent? ? ( "/%s/%s" % [ @parent.class.table_name, @parent.id ] ) : ""
145
+ end
146
+
147
+
148
+ private
149
+
150
+ #
151
+ # use views/../$action.html+mobile.erb if request originates from an iPad
152
+ #
153
+ def set_variant_template
154
+ request.variant = :mobile if request.user_agent =~ /iPad/
155
+ end
156
+
157
+ def resource_options options
158
+ options.merge! params.except( "id", "controller", "action" )
159
+ options = (options.empty? ? "" : "?" + options.collect{ |k,v| "#{k}=#{v}" }.join("&"))
160
+ end
161
+
162
+ #
163
+ # find the resources collection
164
+ def find_resources options
165
+
166
+ params[:ids] ||= []
167
+ params[:ids] << params[:id] unless params[:id].nil?
168
+
169
+ if params[:ids].compact.any?
170
+ policy_scope(resource_class).where(id: params[:ids].compact.split(",").flatten)
171
+ else
172
+ if params[:q].nil? or params[:q]=="" #or params[:q]=="undefined"
173
+ r = parent? ? parent.send(resource_name) : (resource_class.nil? ? nil : policy_scope(resource_class))
174
+ else
175
+ r = find_resources_queried options
176
+ end
177
+
178
+ return r #if params[:print_list]
179
+ # params[:perpage] ||= 20
180
+ # (params[:format].nil? or params[:format]=='html') ? r.page(params[:page]).per(params[:perpage]) : r
181
+ end
182
+
183
+ end
184
+
185
+ #
186
+ # find queried resources collection - implement on each controller to customize
187
+ # raise an exception
188
+ def find_resources_queried options
189
+ case params[:f]
190
+ when nil
191
+ if parent?
192
+ policy_scope(resource_class).tags_included?( params[:q].split(" ") ).where( options )
193
+ else
194
+ policy_scope(resource_class).tags_included?( params[:q].split(" ") )
195
+ end
196
+ else
197
+ policy_scope(resource_class)
198
+ end
199
+ end
200
+ #
201
+ #
202
+ # /employees/1/teams
203
+ # /employees/1/teams/5
204
+ # /employees/1/teams/5/attach
205
+ def find_parent
206
+ if params[:parent].nil?
207
+ return nil if (request.path.split("/").size < 4) or (request.path.split("/").size==4 and %w{edit new}.include?( params[:action]))
208
+ dummy, parent_cls, parent_id, resource_cls, resource_id, action = request.path.split("/")
209
+ parent_cls.singularize.classify.constantize.find(parent_id) rescue nil
210
+ else
211
+ params[:parent].constantize.find(params[:parent_id])
212
+ end
213
+ end
214
+ #
215
+ # # /employees/1/teams/new
216
+ # # /employees/1/teams/1/edit
217
+ # # /employees/1/teams/1/delete
218
+ # def manage_parenthood
219
+ # if params[:parent] and params[:parent_id]
220
+ # parent = params[:parent].classify.constantize.find(params[:parent_id])
221
+ # unless parent.blank?
222
+ # case params[:action]
223
+ # when "create"
224
+ # child = eval("@#{resource_class.to_s.underscore}")
225
+ # children = eval("parent.#{resource_name}")
226
+ # children << child
227
+ # when "edit"
228
+ # when "delete"
229
+ # child = eval("@#{resource_class.to_s.underscore}")
230
+ # children = eval("parent.#{resource_name}")
231
+ # children >> child
232
+ # end
233
+ # end
234
+ # end
235
+ # end
236
+ #
237
+ #
238
+
239
+ def scoop_from_error e
240
+ logger.debug "AbstractResourcesController##{params[:action]}: #{e.class}"
241
+ case e.class.to_s
242
+ when "Pundit::NotAuthorizedError"
243
+ flash.now[:error] = flash[:error] = t('.fail.authorized', resource: resource)
244
+ result = false
245
+ status = 401
246
+ when "ActiveRecord::StatementInvalid" # Mysql2::Error
247
+ flash.now[:error] = flash[:error] = t('fail.mysql_error', mysql: e.to_s)
248
+ result= false
249
+ status = 409
250
+ else
251
+ flash.now[:error] = flash[:error] = "An error occured - please refer to log for details!"
252
+ render head: 412
253
+ end
254
+
255
+
256
+ respond_to do |format|
257
+ case params[:action]
258
+ when 'new'
259
+ format.html { flash.keep(:error) ; redirect_to resources_url }
260
+ format.js { render layout: false, status: status, locals: { result: result} }
261
+ format.json { render json: resources, status: status }
262
+ when 'create'
263
+ format.html { render :new }
264
+ format.js { render layout: false, status: status, locals: { result: result} }
265
+ format.json { render json: resource.errors, status: status }
266
+ when 'show'
267
+ format.html { flash.keep(:error) ; redirect_to resources_url }
268
+ format.js { render layout: false, status: status, locals: { result: result} }
269
+ format.json { render json: resources, status: status }
270
+ when 'edit'
271
+ format.html { flash.keep(:error) ; redirect_to resources_url }
272
+ format.js { render layout: false, status: status, locals: { result: result} }
273
+ format.json { render json: resources, status: status }
274
+ when 'update'
275
+ format.html { render :edit }
276
+ format.js { render layout: false, status: status, locals: { result: result} }
277
+ format.json { render json: resource.errors, status: status }
278
+ when 'index', 'destroy'
279
+ # we should render index - but an error here will not make us happy
280
+ # format.html { render :index }
281
+ #
282
+ format.html { redirect_to root_path, alert: flash[:error] }
283
+ format.js { render layout: false, status: status, locals: { result: result} }
284
+ format.json { render json: resources, status: status }
285
+ end
286
+ end
287
+
288
+ end
289
+
290
+ end