slash_admin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +95 -0
  3. data/app/assets/config/relax_admin_manifest.js +2 -0
  4. data/app/assets/images/slash_admin/en.png +0 -0
  5. data/app/assets/images/slash_admin/favicon.png +0 -0
  6. data/app/assets/images/slash_admin/fr.png +0 -0
  7. data/app/assets/javascripts/slash_admin/application.js +344 -0
  8. data/app/assets/javascripts/slash_admin/custom.js +0 -0
  9. data/app/assets/stylesheets/slash_admin/alert.scss +29 -0
  10. data/app/assets/stylesheets/slash_admin/application.scss +1469 -0
  11. data/app/assets/stylesheets/slash_admin/colors.scss +17 -0
  12. data/app/assets/stylesheets/slash_admin/custom.scss +0 -0
  13. data/app/controllers/slash_admin/application_controller.rb +17 -0
  14. data/app/controllers/slash_admin/base_controller.rb +45 -0
  15. data/app/controllers/slash_admin/batch_actions_controller.rb +17 -0
  16. data/app/controllers/slash_admin/dashboard_controller.rb +11 -0
  17. data/app/controllers/slash_admin/models_controller.rb +325 -0
  18. data/app/controllers/slash_admin/security/sessions_controller.rb +29 -0
  19. data/app/controllers/slash_admin/selectize_controller.rb +49 -0
  20. data/app/helpers/slash_admin/application_helper.rb +212 -0
  21. data/app/helpers/slash_admin/menu_helper.rb +14 -0
  22. data/app/helpers/slash_admin/widgets_helper.rb +7 -0
  23. data/app/jobs/slash_admin/application_job.rb +4 -0
  24. data/app/mailers/slash_admin/application_mailer.rb +6 -0
  25. data/app/models/slash_admin/admin.rb +46 -0
  26. data/app/models/slash_admin/admin_ability.rb +11 -0
  27. data/app/models/slash_admin/application_record.rb +5 -0
  28. data/app/views/layouts/slash_admin/admin_user.html.erb +16 -0
  29. data/app/views/layouts/slash_admin/application.html.erb +40 -0
  30. data/app/views/slash_admin/base/_data_belongs_to.html.erb +37 -0
  31. data/app/views/slash_admin/base/_data_list.html.erb +276 -0
  32. data/app/views/slash_admin/base/_data_nestable.html.erb +33 -0
  33. data/app/views/slash_admin/base/_data_new.html.erb +16 -0
  34. data/app/views/slash_admin/base/_data_show.html.erb +72 -0
  35. data/app/views/slash_admin/base/_filters.html.erb +60 -0
  36. data/app/views/slash_admin/base/_translatable_fields.html.erb +23 -0
  37. data/app/views/slash_admin/base/edit.html.erb +26 -0
  38. data/app/views/slash_admin/base/index.html.erb +47 -0
  39. data/app/views/slash_admin/base/index.xls.erb +27 -0
  40. data/app/views/slash_admin/base/nestable.html.erb +28 -0
  41. data/app/views/slash_admin/base/new.html.erb +26 -0
  42. data/app/views/slash_admin/base/show.html.erb +22 -0
  43. data/app/views/slash_admin/custom_fields/_color.html.erb +2 -0
  44. data/app/views/slash_admin/custom_fields/_email.html.erb +2 -0
  45. data/app/views/slash_admin/custom_fields/_google_map.html.erb +72 -0
  46. data/app/views/slash_admin/custom_fields/_nested_belongs_to.html.erb +55 -0
  47. data/app/views/slash_admin/custom_fields/_password.html.erb +2 -0
  48. data/app/views/slash_admin/custom_fields/_select.html.erb +2 -0
  49. data/app/views/slash_admin/custom_fields/_tags.html.erb +2 -0
  50. data/app/views/slash_admin/custom_fields/_wysiwyg.html.erb +2 -0
  51. data/app/views/slash_admin/dashboard/home.html.erb +5 -0
  52. data/app/views/slash_admin/dashboard/widgets/_statistic_chart.html.erb +0 -0
  53. data/app/views/slash_admin/dashboard/widgets/_statistic_progress_tile.html.erb +29 -0
  54. data/app/views/slash_admin/fields/_belongs_to.html.erb +9 -0
  55. data/app/views/slash_admin/fields/_boolean.html.erb +2 -0
  56. data/app/views/slash_admin/fields/_carrierwave.html.erb +15 -0
  57. data/app/views/slash_admin/fields/_date.html.erb +2 -0
  58. data/app/views/slash_admin/fields/_decimal.html.erb +2 -0
  59. data/app/views/slash_admin/fields/_form_group.html.erb +12 -0
  60. data/app/views/slash_admin/fields/_has_many.html.erb +12 -0
  61. data/app/views/slash_admin/fields/_has_many_row.html.erb +18 -0
  62. data/app/views/slash_admin/fields/_has_one.html.erb +24 -0
  63. data/app/views/slash_admin/fields/_integer.html.erb +2 -0
  64. data/app/views/slash_admin/fields/_json.html.erb +14 -0
  65. data/app/views/slash_admin/fields/_nested_has_many.html.erb +14 -0
  66. data/app/views/slash_admin/fields/_number.html.erb +2 -0
  67. data/app/views/slash_admin/fields/_string.html.erb +2 -0
  68. data/app/views/slash_admin/fields/_text.html.erb +2 -0
  69. data/app/views/slash_admin/security/sessions/new.html.erb +30 -0
  70. data/app/views/slash_admin/shared/_batch_actions.html.erb +21 -0
  71. data/app/views/slash_admin/shared/_better_paginate.html.erb +30 -0
  72. data/app/views/slash_admin/shared/_breadcrumb.html.erb +30 -0
  73. data/app/views/slash_admin/shared/_debug.html.erb +24 -0
  74. data/app/views/slash_admin/shared/_errors_data_new.html.erb +12 -0
  75. data/app/views/slash_admin/shared/_header.html.erb +38 -0
  76. data/app/views/slash_admin/shared/_menu.html.erb +57 -0
  77. data/app/views/slash_admin/shared/_new_form_buttons.html.erb +9 -0
  78. data/app/views/slash_admin/shared/_sub_header.html.erb +11 -0
  79. data/config/initializers/validators.rb +13 -0
  80. data/config/locales/slash_admin.en.yml +67 -0
  81. data/config/locales/slash_admin.fr.yml +72 -0
  82. data/config/routes.rb +16 -0
  83. data/db/migrate/20170512104248_create_slash_admin_admins.rb +19 -0
  84. data/lib/batch_translation.rb +19 -0
  85. data/lib/generators/slash_admin/controllers/controllers_generator.rb +16 -0
  86. data/lib/generators/slash_admin/controllers/templates/controllers.erb +9 -0
  87. data/lib/generators/slash_admin/install/install_generator.rb +13 -0
  88. data/lib/generators/slash_admin/install/templates/install.erb +14 -0
  89. data/lib/generators/slash_admin/override_admin/override_admin_generator.rb +13 -0
  90. data/lib/generators/slash_admin/override_admin/templates/admin.erb +46 -0
  91. data/lib/generators/slash_admin/override_session/override_session_generator.rb +13 -0
  92. data/lib/generators/slash_admin/override_session/templates/session.erb +27 -0
  93. data/lib/generators/slash_admin/permissions/permissions_generator.rb +13 -0
  94. data/lib/generators/slash_admin/permissions/templates/permissions.erb +11 -0
  95. data/lib/slash_admin.rb +29 -0
  96. data/lib/slash_admin/engine.rb +8 -0
  97. data/lib/slash_admin/version.rb +3 -0
  98. data/lib/tasks/slash_admin_tasks.rake +4 -0
  99. data/vendor/assets/javascripts/bootstrap-material-datetimepicker.js +1295 -0
  100. data/vendor/assets/javascripts/codemirror/codemirror.js +9657 -0
  101. data/vendor/assets/javascripts/codemirror/lint/json-lint.js +37 -0
  102. data/vendor/assets/javascripts/codemirror/lint/jsonlint.js +432 -0
  103. data/vendor/assets/javascripts/codemirror/lint/lint.js +252 -0
  104. data/vendor/assets/javascripts/codemirror/mode/javascript.js +865 -0
  105. data/vendor/assets/javascripts/jquery.nestable.js +910 -0
  106. data/vendor/assets/javascripts/jquery.tagsinput-revisited.min.js +5 -0
  107. data/vendor/assets/javascripts/toastr.js +6 -0
  108. data/vendor/assets/stylesheets/animate.css +1579 -0
  109. data/vendor/assets/stylesheets/bootstrap-material-datetimepicker.css +82 -0
  110. data/vendor/assets/stylesheets/codemirror/codemirror.css +346 -0
  111. data/vendor/assets/stylesheets/codemirror/lint/lint.css +73 -0
  112. data/vendor/assets/stylesheets/codemirror/theme/relax-seti.css +41 -0
  113. data/vendor/assets/stylesheets/jquery.nestable.css +121 -0
  114. data/vendor/assets/stylesheets/jquery.tagsinput-revisited.min.css +1 -0
  115. data/vendor/assets/stylesheets/sweetalert.css +935 -0
  116. data/vendor/assets/stylesheets/toastr.css +1 -0
  117. metadata +509 -0
@@ -0,0 +1,17 @@
1
+ // Bootstrap override
2
+ $blue: #659be0 !default;
3
+ $yellow: #f1c40f !default;
4
+ $green: #36c6d3 !default;
5
+ $red: #ed6b75 !default;
6
+
7
+ $success: #26c281;
8
+ $info: #4b77be;
9
+ $error: #e7505a;
10
+ $notice: #f7ca18;
11
+
12
+ // Dasboard
13
+ $primary: #18cdc4;
14
+ $secondary: #26344b;
15
+ $tertiary: #eef1f5;
16
+ $grey: #666;
17
+ $lightgrey: #e1e5ec;
@@ -0,0 +1,17 @@
1
+ module SlashAdmin
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ before_action :set_locale
5
+ helper Rails.application.routes.url_helpers
6
+
7
+ def current_ability
8
+ @current_ability ||= SlashAdmin::AdminAbility.new(current_admin)
9
+ end
10
+
11
+ private
12
+
13
+ def set_locale
14
+ I18n.locale = http_accept_language.compatible_language_from(I18n.available_locales)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,45 @@
1
+ module SlashAdmin
2
+ class BaseController < SlashAdmin::ApplicationController
3
+ before_action :authenticate_admin!
4
+ before_action :handle_default
5
+ before_action :handle_default_mode
6
+ before_action :prepend_view_paths
7
+ helper_method :current_admin, :boolean_to_string
8
+
9
+ protected
10
+
11
+ def handle_default; end
12
+
13
+ def handle_default_mode
14
+ session[:compact] ||= false
15
+ end
16
+
17
+ def prepend_view_paths
18
+ prepend_view_path 'app/views/slash_admin'
19
+ end
20
+
21
+ private
22
+
23
+ def authenticate_admin!
24
+ return true if current_admin.present?
25
+ flash[:error] = t('slash_admin.sessions.login_required')
26
+ redirect_to login_url unless controller_name == 'sessions'
27
+ end
28
+
29
+ def current_admin
30
+ @current_admin ||= SlashAdmin::Admin.find(session[:admin_id]) if session[:admin_id]
31
+ end
32
+
33
+ def to_boolean(str)
34
+ str == 'true'
35
+ end
36
+
37
+ def boolean_to_string(str)
38
+ str ? 'true' : 'false'
39
+ end
40
+
41
+ def should_load_layout_data?
42
+ false
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ module SlashAdmin
3
+ class BatchActionsController < SlashAdmin::BaseController
4
+ def delete
5
+ authorize! :destroy, model
6
+ model.where(id: params[:ids]).delete_all
7
+ end
8
+
9
+ def model
10
+ ActiveRecord::Base.connection.tables.map do |klass|
11
+ testing_class = klass.capitalize.singularize.camelize
12
+ return testing_class.constantize if testing_class == params[:model_class].capitalize.singularize.camelize
13
+ end
14
+ raise Exception.new("Can't find model #{params[:model_class]}")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ module SlashAdmin
3
+ class DashboardController < SlashAdmin::BaseController
4
+ def home; end
5
+
6
+ def toggle
7
+ session[:compact] = session[:compact].blank? ? true : nil
8
+ redirect_to request.referer
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,325 @@
1
+ require 'csv'
2
+
3
+ module SlashAdmin
4
+ class ModelsController < SlashAdmin::BaseController
5
+ before_action :handle_internal_default
6
+ before_action :handle_default
7
+ before_action :nestable_config
8
+ before_action :handle_default_params
9
+ before_action :handle_assocations
10
+
11
+ helper_method :list_params, :export_params, :create_params, :update_params, :show_params, :nested_params, :should_add_translatable?, :translatable_params
12
+
13
+ def index
14
+ authorize! :index, @model_class
15
+ @models_export = if params[:filters].present?
16
+ handle_filtered_search
17
+ else
18
+ @model_class.all
19
+ end
20
+
21
+ column = @model_class.arel_table[params[:order_field].to_sym]
22
+ order = params[:order].downcase
23
+ if %w(asc desc).include?(order)
24
+ @models = @models_export.order(column.send(params[:order].downcase)).page(params[:page]).per(params[:per])
25
+ end
26
+
27
+ @fields = if @use_export_params
28
+ export_params
29
+ else
30
+ @model_class.column_names
31
+ end
32
+
33
+ respond_to do |format|
34
+ format.html
35
+ format.csv { send_data export_csv.encode('iso-8859-1'), filename: "#{@model_name.pluralize.upcase}_#{Date.today}.csv", type: 'text/csv; charset=iso-8859-1; header=present' }
36
+ format.xls { send_data render_to_string, filename: "#{@model_name.pluralize.upcase}_#{Date.today}.xls" }
37
+ format.js { @models }
38
+ end
39
+ end
40
+
41
+ def new
42
+ authorize! :new, @model_class
43
+ @model = @model_class.new
44
+ end
45
+
46
+ def before_validate_on_create; end
47
+ def create
48
+ authorize! :new, @model_class
49
+ @model = @model_class.new(permit_params)
50
+
51
+ before_validate_on_create
52
+
53
+ if @model.valid?
54
+ if @model.save!
55
+ respond_to do |format|
56
+ format.html do
57
+ flash[:success] = t('slash_admin.controller.create.success', model_name: @model_name)
58
+ redirect_to handle_redirect_after_submit and return
59
+ end
60
+ format.js { render json: @model and return }
61
+ end
62
+ end
63
+ else
64
+ flash[:error] = t('slash_admin.controller.create.error', model_name: @model_name)
65
+ end
66
+ respond_to do |format|
67
+ format.html { render :new }
68
+ format.js { render json: { errors: @model.errors.full_messages } }
69
+ end
70
+ end
71
+
72
+ def edit
73
+ authorize! :edit, @model_class
74
+ @model = @model_class.find(params[:id])
75
+ end
76
+
77
+ def before_validate_on_update; end
78
+ def update
79
+ authorize! :edit, @model_class
80
+ @model = @model_class.find(params[:id])
81
+
82
+ before_validate_on_update
83
+
84
+ if @model.update(permit_params)
85
+ flash[:success] = t('slash_admin.controller.update.success', model_name: @model_name)
86
+ respond_to do |format|
87
+ format.html { redirect_to handle_redirect_after_submit and return }
88
+ format.js
89
+ end
90
+ else
91
+ flash[:error] = t('slash_admin.controller.update.error', model_name: @model_name)
92
+ end
93
+ render :edit and return
94
+ end
95
+
96
+ def show
97
+ authorize! :show, @model_class
98
+ @model = @model_class.find(params[:id])
99
+
100
+ respond_to do |format|
101
+ format.html
102
+ format.js { @model }
103
+ end
104
+ end
105
+
106
+ def destroy
107
+ @model_class.find(params[:id]).destroy!
108
+ flash[:success] = t('slash_admin.controller.delete.success', model_name: @model_name)
109
+ respond_to do |format|
110
+ format.html { redirect_to main_app.polymorphic_url([:slash_admin, @model_class]) }
111
+ format.js
112
+ end
113
+ end
114
+
115
+ def nestable
116
+ unless @is_nestable
117
+ flash[:error] = t('slash_admin.controller.nestable.error', model_name: @model_name)
118
+ redirect_to main_app.polymorphic_url([:slash_admin, @model_class]) and return
119
+ end
120
+
121
+ if request.post?
122
+ if params[:nestable][:data].present?
123
+ JSON.parse(params[:nestable][:data]).each_with_index do |p, i|
124
+ m = @model_class.find(p['id'])
125
+ m.position = i
126
+ m.save!
127
+ end
128
+ end
129
+
130
+ flash[:success] = t('slash_admin.controller.nestable.success')
131
+
132
+ redirect_to main_app.polymorphic_url(['slash_admin', @model_class]) and return if params.key?(:submit_redirect)
133
+ redirect_to main_app.polymorphic_url([:nestable, :slash_admin, @model_class])
134
+ end
135
+ end
136
+
137
+ def handle_filtered_search
138
+ search = @model_class.all
139
+
140
+ params[:filters].each do |attr, query|
141
+ unless query.blank?
142
+ # column = @model_class.arel_table[attr.to_sym]
143
+ case helpers.guess_field_type(@model_class, attr)
144
+ when 'string', 'text'
145
+ # TODO: handle unnaccent if postgres and extensions installed
146
+ # search = search.where("unaccent(lower(#{attr})) LIKE unaccent(lower(:query))", query: "%#{query}%")
147
+ search = search.where("lower(#{attr}) LIKE lower(:query)", query: "%#{query}%")
148
+ when 'date', 'datetime'
149
+ if query.is_a?(String)
150
+ search = search.where("#{attr} = :query", query: query)
151
+ else
152
+ if query['from'].present? || query['to'].present?
153
+ if query['from'].to_date != query['to'].to_date
154
+ if query['from'].present?
155
+ search = search.where("#{attr} >= :query", query: query['from'].to_date)
156
+ end
157
+ if query['to'].present?
158
+ search = search.where("#{attr} <= :query", query: query['to'].to_date)
159
+ end
160
+ else
161
+ search = search.where("#{attr} = :query", query: query['from'].to_date)
162
+ end
163
+ end
164
+ end
165
+ when 'decimal', 'number', 'integer'
166
+ search = search.where("#{attr} >= :query", query: query['from']) if query['from'].present?
167
+ search = search.where("#{attr} <= :query", query: query['to']) if query['to'].present?
168
+ when 'boolean'
169
+ search = search.where("#{attr} = :query", query: to_boolean(query))
170
+ when 'belongs_to', 'has_one'
171
+ search = search.where(attr.to_s + '_id IN (' + query.join(',') + ')')
172
+ end
173
+ end
174
+ end
175
+
176
+ search
177
+ end
178
+
179
+ # Export CSV
180
+ def export_csv(options = {})
181
+ CSV.generate(options) do |csv|
182
+ header = @fields.map { |f| @model_class.human_attribute_name(f) }
183
+ csv << header
184
+ @models_export.each do |m|
185
+ csv << m.attributes.values_at(*@fields)
186
+ end
187
+ csv
188
+ end
189
+ end
190
+
191
+ def update_params(options = {})
192
+ if (options.present?)
193
+ create_params(options)
194
+ else
195
+ create_params
196
+ end
197
+ end
198
+
199
+ def autocomplete_params
200
+ aut_params = []
201
+ helpers.object_label_methods.each do |m|
202
+ aut_params << m if model.respond_to? m
203
+ end
204
+
205
+ raise Exception.new('You have to defined autocomplete_params in your admin model controller') if aut_params.blank?
206
+ aut_params
207
+ end
208
+
209
+ protected
210
+
211
+ def prepend_view_paths
212
+ prepend_view_path 'app/views/slash_admin'
213
+ prepend_view_path "app/views/slash_admin/models/#{@model_class.model_name.to_s.pluralize.underscore}" rescue nil
214
+ end
215
+
216
+ def handle_redirect_after_submit
217
+ path = main_app.edit_polymorphic_url(['slash_admin', @model])
218
+ path = main_app.polymorphic_url(['slash_admin', @model_class]) if params.key?(:submit_redirect)
219
+ path = main_app.new_polymorphic_url(['slash_admin', @model_class]) if params.key?(:submit_add)
220
+
221
+ path
222
+ end
223
+
224
+ def permit_params
225
+ params[@model_class.name.split('::').last.underscore].permit!
226
+ end
227
+
228
+ def handle_default
229
+ @title = @model_name.present? ? @model_class.model_name.human(count: 2) : nil
230
+ @sub_title = nil
231
+ @per = 10
232
+ @page = 1
233
+ @per_values = [10, 20, 50, 100, 150]
234
+ @use_export_params = false
235
+ @order_field = :id
236
+ @order = 'DESC'
237
+ end
238
+
239
+ def nestable_config
240
+ @is_nestable = false
241
+ @max_depth = 1
242
+
243
+ @nestable_field = :position
244
+ @acenstry_field = :ancestry
245
+ end
246
+
247
+ def handle_internal_default
248
+ @model_class = model
249
+ @update_params = update_params
250
+ @model_name = @model_class.model_name.human
251
+ end
252
+
253
+ def should_add_translatable?
254
+ should = @model_class.respond_to?(:translated_attribute_names)
255
+ handle_default_translations if should
256
+
257
+ should
258
+ end
259
+
260
+ def handle_default_translations
261
+ I18n.available_locales.reject { |key| key == :root }.each do |locale|
262
+ translation = @model.translations.find_by_locale locale.to_s
263
+ if translation.nil?
264
+ @model.translations.build locale: locale
265
+ end
266
+ end
267
+ end
268
+
269
+ def handle_default_params
270
+ params[:per] ||= @per
271
+ params[:page] ||= @page
272
+ params[:order_field] ||= @order_field
273
+ params[:order] ||= @order
274
+ params[:filters] ||= []
275
+ end
276
+
277
+ def handle_assocations
278
+ @belongs_to_fields = @model_class.reflect_on_all_associations(:belongs_to).map(&:name)
279
+ @has_many_fields = @model_class.reflect_on_all_associations(:has_many).map(&:name)
280
+ @has_one_fields = @model_class.reflect_on_all_associations(:has_one).map(&:name)
281
+ end
282
+
283
+ # By default we are looking in SlashAdmin:: namespace
284
+ def model
285
+ begin
286
+ return controller_name.classify.constantize
287
+ rescue
288
+ return ('SlashAdmin::' + controller_name.classify).constantize
289
+ end
290
+ end
291
+
292
+ def create_params(options = {})
293
+ exclude_default_params(controller_name.classify.constantize.attribute_names).map { |attr| attr.gsub(/_id$/, '') }
294
+ end
295
+
296
+ def translatable_params
297
+ controller_name.classify.constantize.translated_attribute_names
298
+ end
299
+
300
+ def show_params
301
+ @model_class.attribute_names.map { |attr| attr.gsub(/_id$/, '') }
302
+ end
303
+
304
+ def nested_params
305
+ nested_params = []
306
+ @model_class.nested_attributes_options.keys.each do |nested|
307
+ nested_params << { nested => exclude_default_params(nested.to_s.singularize.classify.constantize.attribute_names.map { |attr| attr.gsub(/_id$/, '') }) - [@model.model_name.param_key] }
308
+ end
309
+
310
+ nested_params
311
+ end
312
+
313
+ # Exclude default params for edit and create
314
+ def exclude_default_params(params)
315
+ params - %w(id created_at updated_at slug position)
316
+ end
317
+
318
+ private
319
+ def list_params; end
320
+
321
+ def export_params
322
+ list_params
323
+ end
324
+ end
325
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module SlashAdmin
3
+ module Security
4
+ class SessionsController < ActionController::Base
5
+ protect_from_forgery with: :exception
6
+
7
+ layout 'slash_admin/admin_user'
8
+
9
+ def new; end
10
+
11
+ def create
12
+ admin = Admin.where('username = :value OR lower(email) = lower(:value)', value: params[:admin][:login]).first
13
+ if admin&.authenticate(params[:admin][:password])
14
+ session[:admin_id] = admin.id
15
+ flash[:notice] = 'Vous êtes à présent connecté.'
16
+ redirect_to slash_admin.dashboard_path
17
+ else
18
+ @error_messages = 'Merci de vérifier vos identifiants'
19
+ render :new and return
20
+ end
21
+ end
22
+
23
+ def destroy
24
+ session[:admin_id] = nil
25
+ redirect_to slash_admin.login_url
26
+ end
27
+ end
28
+ end
29
+ end