c80_yax 0.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/CODE_OF_CONDUCT.md +49 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +41 -0
  7. data/Rakefile +2 -0
  8. data/app/admin/c80_yax/items.rb +128 -0
  9. data/app/admin/c80_yax/prop_names.rb +90 -0
  10. data/app/admin/c80_yax/strsubcats.rb +128 -0
  11. data/app/admin/c80_yax/uoms.rb +35 -0
  12. data/app/admin/c80_yax/x_c80_yax.rb +5 -0
  13. data/app/assets/javascripts/backend/items.js +416 -0
  14. data/app/assets/javascripts/c80_yax.js.coffee +6 -0
  15. data/app/assets/javascripts/lib_backend/collapsable-groups.js +22 -0
  16. data/app/assets/javascripts/lib_backend/jalert.js +16 -0
  17. data/app/assets/stylesheets/c80_yax/backend/active_admin/admin_items.scss +152 -0
  18. data/app/assets/stylesheets/c80_yax/backend/collapsed.scss +56 -0
  19. data/app/assets/stylesheets/c80_yax/backend/jquery-my-dialog.scss +22 -0
  20. data/app/assets/stylesheets/c80_yax/lib/loading.scss +13 -0
  21. data/app/assets/stylesheets/c80_yax/mixins.scss +89 -0
  22. data/app/assets/stylesheets/c80_yax_backend.scss +7 -0
  23. data/app/controllers/c80_yax/admin_data_controller.rb +22 -0
  24. data/app/controllers/c80_yax/app_controller.rb +6 -0
  25. data/app/helpers/c80_yax/data_helper.rb +84 -0
  26. data/app/models/c80_yax/iphoto.rb +7 -0
  27. data/app/models/c80_yax/item.rb +169 -0
  28. data/app/models/c80_yax/item_prop.rb +83 -0
  29. data/app/models/c80_yax/prop.rb +5 -0
  30. data/app/models/c80_yax/prop_name.rb +32 -0
  31. data/app/models/c80_yax/strsubcat.rb +71 -0
  32. data/app/models/c80_yax/uom.rb +5 -0
  33. data/app/uploaders/c80_yax/iphoto_uploader.rb +41 -0
  34. data/bin/console +14 -0
  35. data/bin/setup +8 -0
  36. data/c80_yax.gemspec +26 -0
  37. data/config/locales/ru.yml +52 -0
  38. data/config/routes.rb +3 -0
  39. data/db/migrate/20161030061203_create_c80_yax_strsubcats.rb +12 -0
  40. data/db/migrate/20161030225354_create_c80_yax_items.rb +20 -0
  41. data/db/migrate/20161107202727_create_c80_yax_iphotos.rb +11 -0
  42. data/db/migrate/20161107210000_create_c80_yax_props.rb +15 -0
  43. data/db/migrate/20161108095505_create_c80_yax_uoms.rb +11 -0
  44. data/db/migrate/20161108095950_create_c80_yax_prop_names.rb +13 -0
  45. data/db/migrate/20161108100707_create_c80_yax_join_table_prop_names_strsubcats.rb +12 -0
  46. data/db/migrate/20161108102828_create_c80_yax_item_props.rb +13 -0
  47. data/db/seeds/c80_yax_01_fill_props.rb +11 -0
  48. data/lib/c80_yax/engine.rb +23 -0
  49. data/lib/c80_yax/version.rb +3 -0
  50. data/lib/c80_yax.rb +8 -0
  51. metadata +135 -0
@@ -0,0 +1,13 @@
1
+ #loading {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ bottom: 0;
6
+ right: 0;
7
+ text-align: center;
8
+ font-size: 20px;
9
+ background: rgba(255,255,255,0.7) url(data:image/gif;base64,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) 50% 50% no-repeat;
10
+ z-index: 9999;
11
+ border-radius: 5px;
12
+ line-height: 3;
13
+ }
@@ -0,0 +1,89 @@
1
+ // тень
2
+ @mixin shdw($val) {
3
+ -webkit-box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
4
+ -moz-box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
5
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, $val);
6
+ /* For IE 8 */
7
+ -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=$val, Direction=135, Color='#000000')";
8
+ /* For IE 5.5 - 7 */
9
+ filter: progid:DXImageTransform.Microsoft.Shadow(Strength=$val, Direction=135, Color='#000000');
10
+ }
11
+
12
+ @mixin clearfx() {
13
+ &:before,
14
+ &:after {
15
+ content: " ";
16
+ display: table;
17
+ }
18
+ &:after {
19
+ clear: both;
20
+ }
21
+ }
22
+
23
+ // ссылка без подчёркивания и обводки
24
+ //@mixin nounder {
25
+ // text-decoration: none !important;
26
+ // border: none !important;
27
+ // outline: none !important;
28
+ //
29
+ // &:hover, &:active, &:focus {
30
+ // text-decoration: none !important;
31
+ // border: none !important;
32
+ // outline: none !important;
33
+ // }
34
+ //}
35
+
36
+ // анимированный переход цвета
37
+ //@mixin transition_color($sec) {
38
+ // -webkit-transition: color $sec ease-out;
39
+ // -moz-transition: color $sec ease-out;
40
+ // -ms-transition: color $sec ease-out;
41
+ // -o-transition: color $sec ease-out;
42
+ // transition: color $sec ease-out;
43
+ //}
44
+
45
+ // анимированный переход цвета границы
46
+ //@mixin transition_border_color($sec) {
47
+ // -webkit-transition: border-color $sec ease-in;
48
+ // -moz-transition: border-color $sec ease-in;
49
+ // -ms-transition: border-color $sec ease-in;
50
+ // -o-transition: border-color $sec ease-in;
51
+ // transition: border-color $sec ease-in;
52
+ //}
53
+
54
+ //@mixin transform_prop($prop_name,$sec) {
55
+ // -webkit-transition: $prop_name $sec ease-out;
56
+ // -moz-transition: $prop_name $sec ease-out;
57
+ // -ms-transition: $prop_name $sec ease-out;
58
+ // -o-transition: $prop_name $sec ease-out;
59
+ // transition: $prop_name $sec ease-out;
60
+ //}
61
+
62
+ // градиент сверху-вниз
63
+ //@mixin bg_tobottom_gradient($from,$to) {
64
+ // background-image: linear-gradient(to bottom, $from, $to) !important;
65
+ // background: -webkit-gradient(linear, left top, left bottom, from($from), to($to));
66
+ // filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='$from', endColorstr='$to', GradientType=0);
67
+ //}
68
+
69
+ //@mixin transform_scale($scale,$time) {
70
+ // -webkit-transform: scale($scale);
71
+ // -moz-transform: scale($scale);
72
+ // -ms-transform: scale($scale);
73
+ // -o-transform: scale($scale);
74
+ // transform: scale($scale);
75
+ //
76
+ // -webkit-transition: -webkit-transform $time ease-out;
77
+ // -moz-transition: -moz-transform $time ease-out;
78
+ // -ms-transition: -ms-transform $time ease-out;
79
+ // -o-transition: -o-transform $time ease-out;
80
+ // transition: transform $time ease-out;
81
+ //}
82
+
83
+ //@mixin opacity($val) {
84
+ // -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=$val)";
85
+ // filter: alpha(opacity=$val);
86
+ // -moz-opacity:$val;
87
+ // -khtml-opacity: $val;
88
+ // opacity: $val;
89
+ //}
@@ -0,0 +1,7 @@
1
+ //@import "frontend/site/mixins";
2
+ //@import "active_admin/mixins";
3
+
4
+ @import "font-awesome";
5
+ @import 'c80_yax/mixins';
6
+ @import 'c80_yax/lib/**/*';
7
+ @import 'c80_yax/backend/**/*';
@@ -0,0 +1,22 @@
1
+ module C80Yax
2
+ class AdminDataController < ApplicationController
3
+
4
+ # http://stackoverflow.com/questions/5130150/rails-how-to-use-a-helper-inside-a-controller
5
+ include DataHelper
6
+
7
+ def get_strsubcat_propnames
8
+ Rails.logger.debug '[TRACE] <admin_data_controller.get_strsubcat_propnames> Получить список имён свойств данной подкатегории.'
9
+ Rails.logger.debug "[TRACE] <admin_data_controller.get_strsubcat_propnames> request: #{request.request_parameters}"
10
+
11
+ strsubcat_id = request.params[:strsubcat_id]
12
+
13
+ obj = stdh_get_strsubcat_propnames(strsubcat_id)
14
+
15
+ respond_to do |format|
16
+ format.js { render json: obj, status: :ok }
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ module C80Yax
2
+ class AppController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ before_filter :authenticate_admin_user!
5
+ end
6
+ end
@@ -0,0 +1,84 @@
1
+ module C80Yax
2
+
3
+ # хелпер, помогающий с выборкой данных для товаров из категории "строительные материалы"
4
+ module DataHelper
5
+
6
+ include ActiveRecord
7
+
8
+ # собрать все значения свойства prop_name_id из подкатегории sub_cat
9
+ def stdh_collect_all_values(prop_name_id, sub_cat_id)
10
+
11
+ # +---------------------+
12
+ # | prop_23 |
13
+ # +---------------------+
14
+ # | 215 x 102 x 65 мм |
15
+ # | 215 x 48 x 65 мм |
16
+ # | 250 x 85 x 65 мм |
17
+ # | 254 x 95 x 65 мм |
18
+ # | 290 x 90 x 52 мм |
19
+ # | 528 x 108 x 37 мм |
20
+ # +---------------------+
21
+
22
+ table_name = "strcat_#{sub_cat_id}_items"
23
+ column_name = "prop_#{prop_name_id}"
24
+
25
+ sql = "
26
+ SELECT #{table_name}.#{column_name}
27
+ FROM #{table_name}
28
+ GROUP by #{table_name}.#{column_name};
29
+ "
30
+
31
+ ActiveRecord::Base.connection.execute(sql) # => records array
32
+
33
+ end
34
+
35
+ # выдать все характеристики, присущие данной категории, вместе с единицами измерений
36
+ def stdh_get_strsubcat_propnames(strsubcat_id)
37
+
38
+ # +----+----------------+----------------------------+-----------+
39
+ # | id | title | is_excluded_from_filtering | uom_title |
40
+ # +----+----------------+----------------------------+-----------+
41
+ # | 2 | Цена | 0 | руб. |
42
+ # | 3 | Объём | 0 | мл |
43
+ # | 4 | Вкус | 0 | NULL |
44
+ # | 5 | VG/PG | 0 | NULL |
45
+ # | 6 | Никотин | 0 | мг |
46
+ # | 7 | Страна | 0 | NULL |
47
+ # | 19 | Бренд | 0 | NULL |
48
+ # +----+----------------+----------------------------+-----------+
49
+
50
+ # {"id"=>2, "title"=>"Цена", "is_excluded_from_filtering"=>0, "uom_title"=>"руб."},
51
+ # {"id"=>3, "title"=>"Объём", "is_excluded_from_filtering"=>0, "uom_title"=>"мл"},
52
+ # {"id"=>4, "title"=>"Вкус", "is_excluded_from_filtering"=>0, "uom_title"=>nil},
53
+ # {"id"=>5, "title"=>"VG/PG", "is_excluded_from_filtering"=>0, "uom_title"=>nil},
54
+ # {"id"=>6, "title"=>"Никотин", "is_excluded_from_filtering"=>0, "uom_title"=>"мг"},
55
+ # {"id"=>7, "title"=>"Страна", "is_excluded_from_filtering"=>0, "uom_title"=>nil},
56
+ # {"id"=>19, "title"=>"Бренд", "is_excluded_from_filtering"=>0, "uom_title"=>nil}
57
+
58
+ Rails.logger.debug '[TRACE] <stdh_get_strsubcat_propnames> BEGIN'
59
+ sql = "
60
+ SELECT
61
+ `c80_yax_prop_names`.`id`,
62
+ `c80_yax_prop_names`.`title`,
63
+ `c80_yax_prop_names`.`is_excluded_from_filtering`,
64
+ `c80_yax_uoms`.`title` as `uom_title`
65
+ FROM `c80_yax_prop_names`
66
+ INNER JOIN `c80_yax_prop_names_strsubcats` ON `c80_yax_prop_names`.`id` = `c80_yax_prop_names_strsubcats`.`prop_name_id`
67
+ LEFT OUTER JOIN `c80_yax_uoms` ON `c80_yax_uoms`.`id` = `c80_yax_prop_names`.`uom_id`
68
+ WHERE `c80_yax_prop_names_strsubcats`.`strsubcat_id` = #{strsubcat_id};
69
+ "
70
+
71
+ result = []
72
+ rows = Base.connection.execute(sql)
73
+ rows.each(:as => :hash) do |row|
74
+ result << row
75
+ end
76
+
77
+ Rails.logger.debug '[TRACE] <stdh_get_strsubcat_propnames> END'
78
+ result
79
+
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,7 @@
1
+ module C80Yax
2
+ class Iphoto < ActiveRecord::Base
3
+ belongs_to :item
4
+ mount_uploader :image, IphotoUploader
5
+ end
6
+
7
+ end
@@ -0,0 +1,169 @@
1
+ require 'babosa'
2
+
3
+ class C80Yax::Item < ActiveRecord::Base
4
+
5
+ validates :title,
6
+ presence: true,
7
+ uniqueness: true,
8
+ length: { in: 2..150 }
9
+
10
+ validates :strsubcat,
11
+ presence: true
12
+
13
+ # has_and_belongs_to_many :vendors
14
+ belongs_to :strsubcat
15
+
16
+ has_many :iphotos, :dependent => :destroy
17
+ accepts_nested_attributes_for :iphotos,
18
+ :reject_if => lambda { |attributes|
19
+ !attributes.present?
20
+ },
21
+ :allow_destroy => true
22
+
23
+ has_many :item_props, :dependent => :destroy
24
+ accepts_nested_attributes_for :item_props,
25
+ :reject_if => lambda { |attributes|
26
+ # puts "attributes:: #{attributes}"
27
+ # attributes:: {"value"=>"", "prop_name_id"=>""}
28
+ !attributes.present? || \
29
+ !attributes[:value].present? || \
30
+ !attributes[:prop_name_id].present?
31
+ },
32
+ :allow_destroy => true
33
+
34
+ has_many :related_childs, :class_name => 'C80Yax::Item', :foreign_key => 'related_parent_id'
35
+ belongs_to :related_parent, :class_name => 'C80Yax::Item'
36
+
37
+ extend FriendlyId
38
+ friendly_id :slug_candidates, :use => :slugged
39
+
40
+ def slug_candidates
41
+ [:title] + Array.new(6) {|index| [:title, index+2]}
42
+ end
43
+
44
+ def normalize_friendly_id(input)
45
+ input.to_s.to_slug.normalize(transliterations: :russian).to_s
46
+ end
47
+
48
+
49
+
50
+
51
+ # выдать все товары, которые надо показать на главной странице "строительные материалы"
52
+ # с помощью методов ActiveRecord
53
+ def self.all_on_main_ar
54
+
55
+ # * В первую очередь отображаются товары с пометкой "Выводится на главной"
56
+ items_is_main = self.where('is_main = ?',1)
57
+
58
+ # * Далее во вторую очередь выводятся товары, у которых есть обе отметки "hit" и "sale"
59
+ items_is_hit_and_is_sale = self.where('is_hit = ? AND is_sale = ?',1,1)
60
+
61
+ # * Далее выводятся товары, которые отмечены только "hit"
62
+ items_is_hit = self.where('is_hit = ? AND is_sale = ?',1,0)
63
+
64
+ # * Потом товары, которые отмечены только sale
65
+ items_is_sale = self.where('is_sale = ? AND is_hit = ?',1,0)
66
+
67
+ # * А далее все товары, которые по цене (по возрастанию) - от наиболее дешевого товара к наиболее дорогому.
68
+ items_other = self.where.not('is_main = ?',1)
69
+ .where.not('is_hit = ? AND is_sale = ?',1,1)
70
+ .where.not('is_hit = ?',1)
71
+ .where.not('is_sale = ?',1)
72
+
73
+ items_is_main.union(items_is_hit_and_is_sale)
74
+ .union(items_is_hit)
75
+ .union(items_is_sale)
76
+ .union(items_other)
77
+
78
+ end
79
+
80
+ # выдать все товары, которые надо показать на любой странице подкатегории (БЕЗ ФИЛЬТРОВ)
81
+ # с помощью методов ActiveRecord и c80_active_record_union
82
+ def self.all_on_subcat_ar(strsubcat_id)
83
+
84
+ # Сначала выводятся только те, товары, у которых есть обе отметки "hit" и "sale"
85
+ items_is_hit_and_is_sale = self.where('is_hit = ? AND is_sale = ?',1,1)
86
+
87
+ # * Далее выводятся товары, которые отмечены только "hit"
88
+ items_is_hit = self.where('is_hit = ? AND is_sale = ?',1,0)
89
+
90
+ # * Потом товары, которые отмечены только sale
91
+ items_is_sale = self.where('is_sale = ? AND is_hit = ?',1,0)
92
+
93
+ # * А далее все товары, которые по цене (по возрастанию) - от наиболее дешевого товара к наиболее дорогому.
94
+ items_other = self.where.not('is_main = ?',1)
95
+ .where.not('is_hit = ? AND is_sale = ?',1,1)
96
+ .where.not('is_hit = ?',1)
97
+ .where.not('is_sale = ?',1)
98
+
99
+ items_is_hit_and_is_sale.union(items_is_hit)
100
+ .union(items_is_sale)
101
+ .union(items_other)
102
+ .where(:strsubcat_id => strsubcat_id)
103
+
104
+ end
105
+
106
+ before_save :before_save_format_desc
107
+
108
+ # сформировать и вернуть список "похожих товаров"
109
+ def self.get_related_items_list(item_id)
110
+ # Rails.logger.debug("<Item.get_related_items_list> [123] item_id = #{item_id}")
111
+ # Он формируется по следующим правилам:
112
+ # 1. Попадают товары из этой же подкатегории (обязательно, если в подкатегории один товар, то блока просто нет)
113
+ # 2. Тот же бренд
114
+ # 3. Наиболее близкая цена
115
+ # 4. Если есть параметр "Размер", то наиболее близкие по размеру.
116
+ # Также должа быть возможность ручного управления блоком "Похожие товары",
117
+ # где администратор просто указывает ссылки на похожие товары.
118
+
119
+ # результат
120
+ all_related_items = []
121
+
122
+ # кол-во элементов в результате не более этого значения
123
+ n = 4
124
+
125
+ item = self.find(item_id)
126
+
127
+ if item.related_childs.count > 0
128
+ item.related_childs.each do |itm|
129
+ if all_related_items.count < n
130
+ all_related_items << itm
131
+ else
132
+ break
133
+ end
134
+ end
135
+ end
136
+
137
+ all_related_items
138
+
139
+ end
140
+
141
+ private
142
+
143
+ def before_save_format_desc
144
+ if self.full_desc.present?
145
+ v = self.full_desc
146
+
147
+ # удаляем inline css стили
148
+ v = v.gsub(/ style=["'][^"']+["']/, '')
149
+
150
+ # удаляем тэг <font>
151
+ v = v.gsub(/<font[^>]*>/, '')
152
+ v = v.gsub('</font>', '')
153
+
154
+ # <strong>...</strong> заменяем на <span class='bold'>...</span>
155
+ v = v.gsub(/<(em|strong)>/, '<span class="bold">')
156
+ v = v.gsub(/<\/(em|strong)>/, '</span>')
157
+
158
+ # заголовки h1, h2, h3 заменяем на h4
159
+ v = v.gsub(/<(h1|h2|h3)>/, '<h4>')
160
+ v = v.gsub(/<\/(h1|h2|h3)>/, '<h4>')
161
+
162
+ v = v.gsub('&nbsp;', ' ')
163
+
164
+ self.full_desc = v
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,83 @@
1
+ module C80Yax
2
+ class ItemProp < ActiveRecord::Base
3
+ belongs_to :item
4
+ belongs_to :prop_name
5
+
6
+ before_save :before_save_format_value
7
+
8
+ private
9
+
10
+ def self.capz
11
+ [24, # страна
12
+ 36, # бренд
13
+ 46] # бренд (старый)
14
+ end
15
+
16
+ def self.uppz
17
+ [26, # коэф-т теплопроводности
18
+ 27, # морозостойкость
19
+ 38, # формат
20
+ 80, # Марка прочности кирпича (дубликат, созданный заказчиком)
21
+ 75] # марка прочности
22
+ end
23
+
24
+ def self.do_not_touch
25
+ [
26
+ 78, # Завод производитель
27
+ ]
28
+ end
29
+
30
+ def self.siz
31
+ [23] # размер
32
+ end
33
+
34
+ def before_save_format_value
35
+
36
+ v = self.value
37
+ uom = prop_name.uom
38
+
39
+ # удаляем пробелы в начале и в конце строки
40
+ v = v.strip! || v
41
+
42
+ # числовые значения преобразуем в числа
43
+ if uom.present? && uom.is_number
44
+
45
+ v = v.gsub(' ', '')
46
+ v = v.gsub(',', '.')
47
+ v = v[/([0-9.]+)/]
48
+
49
+ # нечисловые значения: либо capitalize, либо upcase, либо downcase
50
+ else
51
+
52
+ if prop_name_id.in?(ItemProp.capz)
53
+ v = v.mb_chars.capitalize.to_s
54
+ elsif prop_name_id.in?(ItemProp.uppz)
55
+ v = v.mb_chars.upcase.to_s
56
+ elsif prop_name_id.in?(ItemProp.do_not_touch)
57
+ v = v
58
+ else
59
+ v = v.mb_chars.downcase.to_s
60
+ end
61
+
62
+ end
63
+
64
+ if prop_name_id.in?(ItemProp.siz)
65
+ v = v.gsub(',', '.')
66
+ sizes = v.scan(/([0-9,]+)/)
67
+ oum = v.scan(/[мс]*м/)
68
+ v = sizes.join(" x ")
69
+ if oum.count > 0
70
+ v += " #{oum[0]}"
71
+ else
72
+ v += ' мм'
73
+ end
74
+ end
75
+
76
+
77
+ self.value = v
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,5 @@
1
+ module C80Yax
2
+ class Prop < ActiveRecord::Base
3
+
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ module C80Yax
2
+ class PropName < ActiveRecord::Base
3
+
4
+ validates :title,
5
+ presence: true,
6
+ uniqueness: true,
7
+ length: { in: 2..150 }
8
+
9
+ # has_many :item_props, :dependent => :destroy
10
+ # has_and_belongs_to_many :strsubcats
11
+ belongs_to :uom
12
+ accepts_nested_attributes_for :uom
13
+
14
+ has_many :im_old_price_and_this_is_link_to_my_normal_price, # NOTE:: поправить, как дойдёт дело
15
+ class_name: 'C80Yax::ItemProp',
16
+ foreign_key: 'related_id'
17
+
18
+ # для цены можно указать старую цену (если она есть)
19
+ belongs_to :related,
20
+ class_name: 'C80Yax::ItemProp'
21
+
22
+ # has_and_belongs_to_many :main_props
23
+ # has_and_belongs_to_many :common_props
24
+ # has_and_belongs_to_many :price_props
25
+
26
+ default_scope {order(:title => :asc)}
27
+
28
+ # validates_with PropNameValidator
29
+ # TODO:: добавить валидацию title на уникальность и длину
30
+
31
+ end
32
+ end
@@ -0,0 +1,71 @@
1
+ require 'babosa'
2
+
3
+ class C80Yax::Strsubcat < ActiveRecord::Base
4
+
5
+ validates :title,
6
+ presence: true,
7
+ uniqueness: true,
8
+ length: { in: 6..50 }
9
+
10
+ has_many :subordinates,
11
+ class_name: 'C80Yax::Strsubcat',
12
+ foreign_key: 'parent_id'
13
+
14
+ belongs_to :parent,
15
+ class_name: 'C80Yax::Strsubcat'
16
+
17
+ has_and_belongs_to_many :prop_names#,
18
+ #:after_add => :after_add_prop_names,
19
+ #:after_remove => :after_remove_prop_names
20
+
21
+ has_many :items, :dependent => :destroy
22
+
23
+ # has_many :main_props, :dependent => :destroy
24
+ # accepts_nested_attributes_for :main_props,
25
+ # :reject_if => lambda { |attributes|
26
+ # !attributes.present?
27
+ # },
28
+ # :allow_destroy => true
29
+ #
30
+ # has_many :price_props, :dependent => :destroy
31
+ # accepts_nested_attributes_for :price_props,
32
+ # :reject_if => lambda { |attributes|
33
+ # !attributes.present?
34
+ # },
35
+ # :allow_destroy => true
36
+ #
37
+ # has_many :common_props, :dependent => :destroy
38
+ # accepts_nested_attributes_for :common_props,
39
+ # :reject_if => lambda { |attributes|
40
+ # !attributes.present?
41
+ # },
42
+ # :allow_destroy => true
43
+
44
+ extend FriendlyId
45
+ friendly_id :slug_candidates, :use => :slugged
46
+
47
+ def slug_candidates
48
+ [:title] + Array.new(6) {|index| [:title, index+2]}
49
+ end
50
+
51
+ def normalize_friendly_id(input)
52
+ input.to_s.to_slug.normalize(transliterations: :russian).to_s
53
+ end
54
+
55
+ scope :menu_order, -> {order(:ord => :asc)}
56
+
57
+ # ------------------------------------------------------------------------------------------------------------------------
58
+
59
+ ransacker :parent_id,
60
+ formatter: proc { |v|
61
+ # Rails.logger.debug "[TRACE] <v> #{v}"
62
+ results = C80Yax::Strsubcat
63
+ .where(:parent_id => v)
64
+ .map(&:id)
65
+ # Rails.logger.debug "[TRACE] <results> #{results}"
66
+ results = results.present? ? results : nil
67
+ }, splat_params: true do |parent|
68
+ parent.table[:id]
69
+ end
70
+
71
+ end
@@ -0,0 +1,5 @@
1
+ module C80Yax
2
+ class Uom < ActiveRecord::Base
3
+ has_one :prop_name
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ module C80Yax
2
+
3
+ # грузит картинку услуги
4
+ class IphotoUploader < BaseFileUploader
5
+
6
+ process :resize_to_limit => [1024,768]
7
+
8
+ version :thumb_sm do
9
+ begin
10
+ p = C80Yax::Prop.first
11
+ process :resize_to_fill => [p.thumb_sm_width, p.thumb_sm_height]
12
+ rescue => e
13
+ Rails.logger.debug "[TRACE] <iphoto_uploader.thumb_sm> [ERROR] #{e}"
14
+ end
15
+ end
16
+
17
+ version :thumb_md do
18
+ begin
19
+ p = C80Yax::Prop.first
20
+ process :resize_to_fill => [p.thumb_md_width, p.thumb_md_height]
21
+ rescue => e
22
+ Rails.logger.debug "[TRACE] <iphoto_uploader.thumb_md> [ERROR] #{e}"
23
+ end
24
+ end
25
+
26
+ version :thumb_lg do
27
+ begin
28
+ p = C80Yax::Prop.first
29
+ process :resize_to_fill => [p.thumb_lg_width, p.thumb_lg_height]
30
+ rescue => e
31
+ Rails.logger.debug "[TRACE] <iphoto_uploader.thumb_lg> [ERROR] #{e}"
32
+ end
33
+ end
34
+
35
+ def store_dir
36
+ 'uploads/items'
37
+ end
38
+
39
+ end
40
+
41
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "c80_yax"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start