caboose-cms 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -103,6 +103,23 @@ module Caboose
103
103
  end
104
104
  render :json => options
105
105
  end
106
+
107
+ # GET /admin/categories/options
108
+ def admin_options
109
+ options = []
110
+ cat = Category.find(1)
111
+ cat.children.each do |c|
112
+ admin_options_helper(options, c, '')
113
+ end
114
+ render :json => options
115
+ end
116
+
117
+ def admin_options_helper(options, cat, prefix)
118
+ options << { :value => cat.id, :text => "#{prefix}#{cat.name}" }
119
+ cat.children.each do |c|
120
+ admin_options_helper(options, c, "#{prefix} - ")
121
+ end
122
+ end
106
123
  end
107
124
  end
108
125
 
@@ -295,6 +295,38 @@ module Caboose
295
295
  render :layout => 'caboose/admin'
296
296
  end
297
297
 
298
+ # GET /admin/products/json
299
+ def admin_json
300
+ return if !user_is_allowed('products', 'view')
301
+
302
+ # Temporary patch for vendor name sorting; Fix this
303
+ params[:sort] = 'store_vendors.name' if params[:sort] == 'vendor'
304
+
305
+ pager = Caboose::PageBarGenerator.new(params, {
306
+ 'vendor_name' => '',
307
+ 'search_like' => '',
308
+ 'price' => params[:filters] && params[:filters][:missing_prices] ? 0 : ''
309
+ }, {
310
+ 'model' => 'Caboose::Product',
311
+ 'sort' => 'title',
312
+ 'desc' => false,
313
+ 'base_url' => '/admin/products',
314
+ 'items_per_page' => 25,
315
+ 'use_url_params' => false,
316
+ 'abbreviations' => {
317
+ 'search_like' => 'store_products.title_concat_vendor_name_like'
318
+ },
319
+ 'includes' => {
320
+ 'vendor_name' => [ 'vendor' , 'name' ],
321
+ 'price' => [ 'variants' , 'price' ]
322
+ }
323
+ })
324
+ render :json => {
325
+ :pager => pager,
326
+ :models => pager.items.as_json(:includes => [:vendor, :categories])
327
+ }
328
+ end
329
+
298
330
  # GET /admin/products/add-upcs - TODO remove this; it's a temporary thing for woods-n-water
299
331
  def admin_add_upcs
300
332
  params[:vendor_id] if params[:vendor_id] and params[:vendor_id].empty?
@@ -312,7 +344,13 @@ module Caboose
312
344
 
313
345
  render :layout => 'caboose/admin'
314
346
  end
315
-
347
+
348
+ # GET /admin/products/:id/json
349
+ def admin_json_single
350
+ p = Product.find(params[:id])
351
+ render :json => p.as_json(:includes => [:vendor, :categories])
352
+ end
353
+
316
354
  # GET /admin/products/:id/general
317
355
  def admin_edit_general
318
356
  return if !user_is_allowed('products', 'edit')
@@ -533,43 +571,20 @@ module Caboose
533
571
  save = true
534
572
  params.each do |name,value|
535
573
  case name
536
- when 'alternate_id'
537
- product.alternate_id = value
538
- when 'date_available'
539
- if value.strip.length == 0
540
- product.date_available = nil
541
- else
542
- begin
543
- product.date_available = DateTime.parse(value)
544
- rescue
545
- resp.error = "Invalid date"
546
- save = false
547
- end
548
- end
549
- when 'title'
550
- product.title = value
551
- when 'caption'
552
- product.caption = value
553
- when 'featured'
554
- product.featured = value
555
- when 'description'
556
- product.description = value
557
- when 'category_id'
558
- product.category_id = value
559
- when 'vendor_id'
560
- product.vendor_id = value
561
- when 'handle'
562
- product.handle = value
563
- when 'seo_title'
564
- product.seo_title = value
565
- when 'seo_description'
566
- product.seo_description = value
567
- when 'option1'
568
- product.option1 = value
569
- when 'option2'
570
- product.option2 = value
571
- when 'option3'
572
- product.option3 = value
574
+ when 'alternate_id' then product.alternate_id = value
575
+ when 'title' then product.title = value
576
+ when 'caption' then product.caption = value
577
+ when 'featured' then product.featured = value
578
+ when 'description' then product.description = value
579
+ when 'vendor_id' then product.vendor_id = value
580
+ when 'handle' then product.handle = value
581
+ when 'seo_title' then product.seo_title = value
582
+ when 'seo_description' then product.seo_description = value
583
+ when 'status' then product.status = value
584
+ when 'category_id' then product.toggle_category(value[0], value[1])
585
+ when 'option1' then product.option1 = value
586
+ when 'option2' then product.option2 = value
587
+ when 'option3' then product.option3 = value
573
588
  when 'default1'
574
589
  product.default1 = value
575
590
  Variant.where(:product_id => product.id, :option1 => nil).each do |p|
@@ -587,9 +602,18 @@ module Caboose
587
602
  Variant.where(:product_id => product.id, :option3 => nil).each do |p|
588
603
  p.option3 = value
589
604
  p.save
605
+ end
606
+ when 'date_available'
607
+ if value.strip.length == 0
608
+ product.date_available = nil
609
+ else
610
+ begin
611
+ product.date_available = DateTime.parse(value)
612
+ rescue
613
+ resp.error = "Invalid date"
614
+ save = false
615
+ end
590
616
  end
591
- when 'status'
592
- product.status = value
593
617
  end
594
618
  end
595
619
  resp.success = save && product.save
@@ -141,5 +141,25 @@ module Caboose
141
141
  def option3_values
142
142
  self.variants.where(:status => 'Active').reorder(:option3_sort_order).pluck(:option3).uniq.reject { |x| x.nil? || x.empty? }
143
143
  end
144
+
145
+ def toggle_category(cat_id, value)
146
+ if value.to_i > 0 # Add to category
147
+ if cat_id == 'all'
148
+ CategoryMembership.where(:product_id => self.id).destroy_all
149
+ Category.reorder(:name).all.each{ |cat| CategoryMembership.create(:product_id => self.id, :category_id => cat.id) }
150
+ else
151
+ if !CategoryMembership.where(:product_id => self.id, :category_id => cat_id.to_i).exists?
152
+ CategoryMembership.create(:product_id => self.id, :category_id => cat_id.to_i)
153
+ end
154
+ end
155
+ else # Remove from category
156
+ if cat_id == 'all'
157
+ CategoryMembership.where(:product_id => self.id).destroy_all
158
+ else
159
+ CategoryMembership.where(:product_id => self.id, :category_id => cat_id.to_i).destroy_all
160
+ end
161
+ end
162
+ end
163
+
144
164
  end
145
165
  end
@@ -1,95 +1,87 @@
1
1
  <h1>Products</h1>
2
2
 
3
3
  <p style="margin: 12px 0">
4
- <a href="/admin/vendors/new">New Vendor</a>
5
- <span style="margin: 0 3px">|</span>
6
- <a href="/admin/products/new">New Product</a>
7
- <span style="margin: 0 3px">|</span>
8
- <a href="/admin/products/sort">Sort Products</a>
4
+ <a href="/admin/vendors/new">New Vendor</a><span style="margin: 0 3px">|</span>
5
+ <a href="/admin/products/new">New Product</a><span style="margin: 0 3px">|</span>
6
+ <a href="/admin/products/sort">Sort Products</a><span style="margin: 0 3px">|</span>
7
+ <a href='#'>Search Form</a>
9
8
  </p>
10
9
 
11
- <div class="media">
12
- <aside class="right">
13
- <form action="/admin/products" method="get" id="search_form" style="margin: 0 0 12px">
14
- <input type="text" name="search_like" placeholder="Title or Vendor Name" value="<%= params[:search_like] %>" style="width: 350px" />
15
- <input type="submit" value="Search" />
16
- <input type="button" value="Clear" onclick="window.location='/admin/products'" />
17
-
18
- <ul>
19
- <li><p>Find products that have:</p></li>
20
- <li><label><input name="filters[missing_prices]" type="checkbox" <%= 'checked="checked"' if params[:filters] && params[:filters][:missing_prices] %> /> Missing prices</label></li>
21
- <li><label><input name="filters[missing_images]" type="checkbox" <%= 'checked="checked"' if params[:filters] && params[:filters][:missing_images] %> /> Missing images</label></li>
22
- <li><label><input name="filters[no_vendor]" type="checkbox" <%= 'checked="checked"' if params[:filters] && params[:filters][:no_vendor] %> /> No vendor</label></li>
23
- </ul>
24
- </form>
25
- </aside>
10
+ <form action="/admin/products" method="get" id="search_form" style="margin: 0 0 12px">
11
+ <input type="text" name="search_like" placeholder="Title or Vendor Name" value="<%= params[:search_like] %>" style="width: 350px" />
12
+ <input type="submit" value="Search" />
13
+ <input type="button" value="Clear" onclick="window.location='/admin/products'" />
14
+ </form>
26
15
 
27
- <section>
28
- <% if @products.count > 0 %>
29
- <table class='data' id='properties_table'>
30
- <tr>
31
- <%= raw @gen.sortable_table_headings({
32
- 'id' => 'ID',
33
- 'title' => 'Title',
34
- 'vendor' => 'Vendor'
35
- }) %>
36
- </tr>
37
-
38
- <% @products.each do |p| %>
39
- <tr onclick="window.location='/admin/products/<%= p.id %>/general';">
40
- <td><%= raw p.id %></td>
41
- <td><%= raw p.title %></td>
42
- <td><%= raw p.vendor.nil? ? 'Unknown' : p.vendor.name %></td>
43
- </tr>
44
- <% end %>
45
- </table>
46
-
47
- <p><%= raw @gen.generate %></p>
48
- <% else %>
49
- <p>There are no products right now.</p>
50
- <% end %>
51
- </section>
52
- </div>
16
+ <div id='products'></div>
53
17
 
54
- <% content_for :caboose_css do %>
55
- <style>
56
- ul {
57
- list-style-type: none;
58
- padding: 0;
59
- }
60
- input[type=checkbox] {
61
- height: 16px;
62
- left: auto !important;
63
- margin: 0 0 12px !important;
64
- position: relative !important;
65
- top: auto !important;
66
- }
67
- label { cursor: pointer; }
68
- label input[type=checkbox] {
69
- height: 15px !important;
70
- left: auto !important;
71
- margin: 12px 0 !important;
72
- position: relative !important;
73
- top: auto !important;
74
- }
75
-
76
- .media,
77
- .media > section { overflow: hidden; }
78
- .media > aside {
79
- float: left;
80
- margin-right: 12px;
81
- }
82
- .media > aside.right {
83
- float: right;
84
- margin-left: 12px;
85
- }
86
- </style>
18
+ <% content_for :caboose_js do %>
19
+ <%= javascript_include_tag 'caboose/model/all' %>
20
+ <script type='text/javascript'>
21
+
22
+ $(document).ready(function() {
23
+ var that = this;
24
+ var table = new IndexTable({
25
+ form_authenticity_token: '<%= form_authenticity_token %>',
26
+ container: 'products',
27
+ base_url: '/admin/products',
28
+ allow_bulk_edit: false,
29
+ allow_bulk_delete: false,
30
+ allow_duplicate: false,
31
+ fields: [
32
+ { show: true , name: 'id' , nice_name: 'ID' , sort: 'id' , type: 'text' , value: function(p) { return p.id }, width: 500, editable: false },
33
+ { show: true , name: 'title' , nice_name: 'Title' , sort: 'title' , type: 'text' , value: function(p) { return p.title }, width: 200 },
34
+ { show: true , name: 'caption' , nice_name: 'Caption' , sort: 'caption' , type: 'text' , value: function(p) { return p.caption }, width: 200 },
35
+ { show: true , name: 'status' , nice_name: 'Status' , sort: 'status' , type: 'select' , value: function(p) { return p.status }, width: 200, options_url: '/admin/products/status-options' },
36
+ { show: true , name: 'handle' , nice_name: 'URL Handle' , sort: 'handle' , type: 'text' , value: function(p) { return p.handle }, width: 200 },
37
+ { show: true , name: 'seo_title' , nice_name: 'SEO Page Title' , sort: 'seo_title' , type: 'text' , value: function(p) { return p.seo_title }, width: 200 },
38
+ { show: false, name: 'seo_description' , nice_name: 'SEO Meta Description' , sort: 'seo_description' , type: 'textarea' , value: function(p) { return p.seo_description }, width: 200, height: 150 },
39
+ { show: true , name: 'alternate_id' , nice_name: 'Alternate ID' , sort: 'alternate_id' , type: 'text' , value: function(p) { return p.alternate_id }, width: 200 },
40
+ { show: true , name: 'date_available' , nice_name: 'Date Available' , sort: 'date_available' , type: 'date' , value: function(p) { return p.date_available }, width: 200 },
41
+ { show: false, name: 'featured' , nice_name: 'Featured' , sort: 'featured' , type: 'checkbox' , value: function(p) { return p.featured }, width: 200 },
42
+ { show: false, name: 'category_id' , nice_name: 'Categories' , sort: 'categories.name' , type: 'checkbox-multiple' , value: function(p) { return p.categories ? p.categories.map(function(c) { return c.id }) : []; }, text: function(p) { return p.categories ? p.categories.map(function(c) { return c.name }).join(', ') : ''; }, width: 200, height: 200, options_url: '/admin/categories/options' },
43
+ ],
44
+ new_model_text: 'New Product',
45
+ new_model_fields: [
46
+ { name: 'name', nice_name: 'Name', type: 'text', width: 400 }
47
+ ],
48
+ });
49
+ });
50
+
51
+ </script>
87
52
  <% end %>
88
53
 
89
- <% content_for :caboose_js do %>
90
- <script type='text/javascript'>
91
- $(document).ready(function() {
92
- var modal = new CabooseModal(800);
93
- });
94
- </script>
54
+ <% content_for :caboose_css do %>
55
+ <style>
56
+ ul {
57
+ list-style-type: none;
58
+ padding: 0;
59
+ }
60
+ input[type=checkbox] {
61
+ height: 16px;
62
+ left: auto !important;
63
+ margin: 0 0 12px !important;
64
+ position: relative !important;
65
+ top: auto !important;
66
+ }
67
+ label { cursor: pointer; }
68
+ label input[type=checkbox] {
69
+ height: 15px !important;
70
+ left: auto !important;
71
+ margin: 12px 0 !important;
72
+ position: relative !important;
73
+ top: auto !important;
74
+ }
75
+
76
+ .media,
77
+ .media > section { overflow: hidden; }
78
+ .media > aside {
79
+ float: left;
80
+ margin-right: 12px;
81
+ }
82
+ .media > aside.right {
83
+ float: right;
84
+ margin-left: 12px;
85
+ }
86
+ </style>
95
87
  <% end %>
data/config/routes.rb CHANGED
@@ -50,7 +50,7 @@ Caboose::Engine.routes.draw do
50
50
  post "admin/users/import" => "users#import"
51
51
  get "admin/users/:id/su" => "users#admin_su"
52
52
  get "admin/users/:id/edit-password" => "users#edit_password"
53
- get "admin/users/:id/edit" => "users#edit"
53
+ get "admin/users/:id" => "users#edit"
54
54
  put "admin/users/:id" => "users#update"
55
55
  post "admin/users" => "users#create"
56
56
  delete "admin/users/:id" => "users#destroy"
@@ -61,7 +61,7 @@ Caboose::Engine.routes.draw do
61
61
  get "admin/roles" => "roles#index"
62
62
  get "admin/roles/options" => "roles#options"
63
63
  get "admin/roles/new" => "roles#new"
64
- get "admin/roles/:id/edit" => "roles#edit"
64
+ get "admin/roles/:id" => "roles#edit"
65
65
  put "admin/roles/:id" => "roles#update"
66
66
  post "admin/roles" => "roles#create"
67
67
  delete "admin/roles/:id" => "roles#destroy"
@@ -89,7 +89,7 @@ Caboose::Engine.routes.draw do
89
89
  get "admin/permissions" => "permissions#index"
90
90
  get "admin/permissions/options" => "permissions#options"
91
91
  get "admin/permissions/new" => "permissions#new"
92
- get "admin/permissions/:id/edit" => "permissions#edit"
92
+ get "admin/permissions/:id" => "permissions#edit"
93
93
  put "admin/permissions/:id" => "permissions#update"
94
94
  post "admin/permissions" => "permissions#create"
95
95
  delete "admin/permissions/:id" => "permissions#destroy"
@@ -97,7 +97,7 @@ Caboose::Engine.routes.draw do
97
97
  get "admin/settings" => "settings#index"
98
98
  get "admin/settings/options" => "settings#options"
99
99
  get "admin/settings/new" => "settings#new"
100
- get "admin/settings/:id/edit" => "settings#edit"
100
+ get "admin/settings/:id" => "settings#edit"
101
101
  put "admin/settings/:id" => "settings#update"
102
102
  post "admin/settings" => "settings#create"
103
103
  delete "admin/settings/:id" => "settings#destroy"
@@ -112,8 +112,7 @@ Caboose::Engine.routes.draw do
112
112
  get "admin/pages/:id/block-options" => "pages#admin_block_options"
113
113
  get "admin/pages/:id/uri" => "pages#admin_page_uri"
114
114
  get "admin/pages/:id/delete" => "pages#admin_delete_form"
115
- get "admin/pages/:id/sitemap" => "pages#admin_sitemap"
116
- get "admin/pages/:id/edit" => "pages#admin_edit_general"
115
+ get "admin/pages/:id/sitemap" => "pages#admin_sitemap"
117
116
  get "admin/pages/:id/permissions" => "pages#admin_edit_permissions"
118
117
  get "admin/pages/:id/css" => "pages#admin_edit_css"
119
118
  get "admin/pages/:id/js" => "pages#admin_edit_js"
@@ -127,7 +126,8 @@ Caboose::Engine.routes.draw do
127
126
  get "admin/pages/:id/layout" => "pages#admin_edit_layout"
128
127
  put "admin/pages/:id/layout" => "pages#admin_update_layout"
129
128
  put "admin/pages/:id/viewers" => "pages#admin_update_viewers"
130
- put "admin/pages/:id/editors" => "pages#admin_update_editors"
129
+ put "admin/pages/:id/editors" => "pages#admin_update_editors"
130
+ get "admin/pages/:id" => "pages#admin_edit_general"
131
131
  put "admin/pages/:id" => "pages#admin_update"
132
132
  get "admin/pages" => "pages#admin_index"
133
133
  post "admin/pages" => "pages#admin_create"
@@ -283,12 +283,12 @@ Caboose::Engine.routes.draw do
283
283
 
284
284
  get '/admin/products/add-upcs' => 'products#admin_add_upcs'
285
285
 
286
- get '/admin/vendors' => 'vendors#admin_index'
287
- get '/admin/vendors/status-options' => 'vendors#status_options'
286
+ get '/admin/vendors/status-options' => 'vendors#status_options'
288
287
  get '/admin/vendors/new' => 'vendors#admin_new'
289
- get '/admin/vendors/:id/edit' => 'vendors#admin_edit'
290
- post '/admin/vendors/create' => 'vendors#admin_create'
291
- put '/admin/vendors/:id/update' => 'vendors#admin_update'
288
+ get '/admin/vendors/:id' => 'vendors#admin_edit'
289
+ put '/admin/vendors/:id' => 'vendors#admin_update'
290
+ post '/admin/vendors' => 'vendors#admin_add'
291
+ get '/admin/vendors' => 'vendors#admin_index'
292
292
 
293
293
  # Orders
294
294
 
@@ -298,35 +298,38 @@ Caboose::Engine.routes.draw do
298
298
 
299
299
  post "/reviews/add" => "reviews#add"
300
300
 
301
- get "/admin/products" => "products#admin_index"
302
- get '/admin/products/sort' => 'products#admin_sort'
303
- put '/admin/products/update-sort-order' => 'products#admin_update_sort_order'
304
- put "/admin/products/update-vendor-status/:id" => "products#admin_update_vendor_status"
305
- get "/admin/products/new" => "products#admin_new"
306
- get "/admin/products/status-options" => "products#admin_status_options"
307
- get "/admin/products/:id/general" => "products#admin_edit_general"
308
- get "/admin/products/:id/description" => "products#admin_edit_description"
309
- get "/admin/products/:id/categories" => "products#admin_edit_categories"
310
- post "/admin/products/:id/categories" => "products#admin_add_to_category"
311
- delete "/admin/products/:id/categories/:category_id" => "products#admin_remove_from_category"
312
- get "/admin/products/:id/variants" => "products#admin_edit_variants"
313
- get "/admin/products/:id/variants/json" => "products#admin_variants_json"
314
- get "/admin/products/:id/variant-cols" => "products#admin_edit_variant_columns"
315
- put "/admin/products/:id/variant-cols" => "products#admin_update_variant_columns"
316
- get "/admin/products/:id/variants/sort-order" => "products#admin_edit_variant_sort_order"
301
+ get "/admin/products" => "products#admin_index"
302
+ get "/admin/products/json" => "products#admin_json"
303
+ get '/admin/products/sort' => 'products#admin_sort'
304
+ put '/admin/products/update-sort-order' => 'products#admin_update_sort_order'
305
+ put "/admin/products/update-vendor-status/:id" => "products#admin_update_vendor_status"
306
+ get "/admin/products/new" => "products#admin_new"
307
+ get "/admin/products/status-options" => "products#admin_status_options"
308
+ get "/admin/products/:id/general" => "products#admin_edit_general"
309
+ get "/admin/products/:id/description" => "products#admin_edit_description"
310
+ get "/admin/products/:id/categories" => "products#admin_edit_categories"
311
+ post "/admin/products/:id/categories" => "products#admin_add_to_category"
312
+ delete "/admin/products/:id/categories/:category_id" => "products#admin_remove_from_category"
313
+ get "/admin/products/:id/variants" => "products#admin_edit_variants"
314
+ get "/admin/products/:id/variants/json" => "products#admin_variants_json"
315
+ get "/admin/products/:id/variant-cols" => "products#admin_edit_variant_columns"
316
+ put "/admin/products/:id/variant-cols" => "products#admin_update_variant_columns"
317
+ get "/admin/products/:id/variants/sort-order" => "products#admin_edit_variant_sort_order"
317
318
  put '/admin/products/:id/variants/option1-sort-order' => 'products#admin_update_variant_option1_sort_order'
318
319
  put '/admin/products/:id/variants/option2-sort-order' => 'products#admin_update_variant_option2_sort_order'
319
320
  put '/admin/products/:id/variants/option3-sort-order' => 'products#admin_update_variant_option3_sort_order'
320
- get "/admin/products/:id/images" => "products#admin_edit_images"
321
- post "/admin/products/:id/images" => "products#admin_add_image"
322
- get "/admin/products/:id/collections" => "products#admin_edit_collections"
323
- get "/admin/products/:id/seo" => "products#admin_edit_seo"
324
- get "/admin/products/:id/options" => "products#admin_edit_options"
325
- get "/admin/products/:id/delete" => "products#admin_delete_form"
326
- put "/admin/products/:id" => "products#admin_update"
327
- post "/admin/products" => "products#admin_add"
328
- delete "/admin/products/:id" => "products#admin_delete"
329
- put "/admin/products/:id/update-vendor" => "products#admin_update_vendor"
321
+ get "/admin/products/:id/images" => "products#admin_edit_images"
322
+ post "/admin/products/:id/images" => "products#admin_add_image"
323
+ get "/admin/products/:id/collections" => "products#admin_edit_collections"
324
+ get "/admin/products/:id/seo" => "products#admin_edit_seo"
325
+ get "/admin/products/:id/options" => "products#admin_edit_options"
326
+ get "/admin/products/:id/delete" => "products#admin_delete_form"
327
+ get "/admin/products/:id/json" => "products#admin_json_single"
328
+ get "/admin/products/:id" => "products#admin_edit_general"
329
+ put "/admin/products/:id" => "products#admin_update"
330
+ post "/admin/products" => "products#admin_add"
331
+ delete "/admin/products/:id" => "products#admin_delete"
332
+ put "/admin/products/:id/update-vendor" => "products#admin_update_vendor"
330
333
 
331
334
  get "/admin/products/:product_id/variants/:variant_id/edit" => "variants#admin_edit"
332
335
  get "/admin/variants/status-options" => "variants#admin_status_options"
@@ -341,7 +344,7 @@ Caboose::Engine.routes.draw do
341
344
  get "/admin/categories" => "categories#admin_index"
342
345
  get "/admin/categories/new" => "categories#admin_new"
343
346
  get "/admin/categories/options" => "categories#admin_options"
344
- get "/admin/categories/:id/edit" => "categories#admin_edit"
347
+ get "/admin/categories/:id" => "categories#admin_edit"
345
348
  put "/admin/categories/:id" => "categories#admin_update"
346
349
  get '/admin/categories/status-options' => 'categories#admin_status_options'
347
350
  post "/admin/categories/:id" => "categories#admin_update"