rails_com 1.2.0 → 1.2.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -4
  3. data/app/assets/javascripts/rails_com/checkbox.js +59 -0
  4. data/app/assets/javascripts/rails_com/common.js +5 -2
  5. data/app/assets/javascripts/rails_com/fetch_xhr_script.js +3 -37
  6. data/app/assets/javascripts/rails_com/sidebar.js +40 -0
  7. data/app/controllers/common_controller.rb +0 -8
  8. data/app/controllers/concerns/the_common_api.rb +2 -2
  9. data/app/helpers/rails_com/active_helper.rb +1 -0
  10. data/app/helpers/{rails_com_helper.rb → rails_com/assets_helper.rb} +2 -10
  11. data/app/helpers/rails_com/common_helper.rb +13 -0
  12. data/app/helpers/rails_com/time_helper.rb +22 -0
  13. data/app/models/state_machine.rb +63 -15
  14. data/app/views/shared/_locales.html.erb +1 -1
  15. data/config/locales/en.yml +7 -1
  16. data/config/locales/zh.datetime.yml +44 -0
  17. data/config/locales/zh.yml +9 -0
  18. data/config/routes.rb +0 -4
  19. data/lib/mina/puma.rb +3 -2
  20. data/lib/mina/whenever.rb +27 -0
  21. data/lib/rails_com/config.rb +11 -0
  22. data/lib/rails_com/core_ext/array.rb +54 -0
  23. data/lib/rails_com/model_helper.rb +55 -4
  24. data/lib/rails_com/rails_ext/activestorage_attached.rb +32 -0
  25. data/lib/rails_com/rails_ext/persistence_sneakily.rb +11 -0
  26. data/lib/rails_com/rails_ext/scaffold_generator.rb +1 -0
  27. data/lib/rails_com/rails_ext/template_renderer.rb +3 -3
  28. data/lib/rails_com/rails_ext/translation_helper.rb +18 -0
  29. data/lib/rails_com/routes.rb +5 -0
  30. data/lib/rails_com/setting.rb +34 -0
  31. data/lib/rails_com/version.rb +1 -1
  32. data/lib/rails_com.rb +7 -5
  33. data/lib/templates/erb/scaffold/_search_form.html.erb.tt +1 -1
  34. data/lib/templates/erb/scaffold/edit.html.erb.tt +7 -12
  35. data/lib/templates/erb/scaffold/index.html.erb.tt +32 -36
  36. data/lib/templates/erb/scaffold/new.html.erb.tt +8 -12
  37. data/lib/utils/ip_helper.rb +21 -0
  38. data/lib/utils/time_helper.rb +37 -0
  39. metadata +17 -12
  40. data/config/initializers/time_format.rb +0 -1
  41. data/lib/assets/javascripts/semantic.js +0 -11
  42. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.eot +0 -0
  43. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.otf +0 -0
  44. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.svg +0 -947
  45. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.ttf +0 -0
  46. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.woff +0 -0
  47. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.woff2 +0 -0
  48. data/lib/nondigest_assets/fonts/themes/default/assets/images/flags.png +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91a9e381fa905dd733cdabed0016d6f6826b468e3d9a2d1af8eece1323d88d81
4
- data.tar.gz: 95625b665362ccfea08fb4f9317a521e741adc0f765d0bef2996477aef0cc34c
3
+ metadata.gz: 2ffa9f1ff257d36fdc9bb11415039affae4ee7a1589f7c15f565e911ca6fe33a
4
+ data.tar.gz: 36054a13e2f3a8b7ea8c8130dcb16185612bc8b575c701eaaf0630b6c8f0ce0c
5
5
  SHA512:
6
- metadata.gz: 0ce5ae23bc46a4f2d667db8d8b21ee86b4fa8670a322074857d1cee11b0a6afd7c3e8c8cce0325cc15a6b65742c25dec7b486a48bb964e971df62f9d3b21734c
7
- data.tar.gz: a6f1f3e942c26a68ad460f387146fe58304895fa8c46ac76c9f9053fcbf270ca4cd7288bb0cb5a6d4839275099e18ad1282fe517cfea796e34f52e508cb257c9
6
+ metadata.gz: 27c0ff46020d0a06076a4c085deea1ce604434b97836232c3ccea537b05b20c7be7960cf2dad3786dfa365f1a85994e7f4b8bc68e9a759c7dd8e598a98e31f95
7
+ data.tar.gz: 0d745dbbe1560f2ccfb5fe2a6172ef3180903bec46aa8f40b59d864bb9b447ae8157719c7ed05822086c468a27e82282085e02709720357534af651c247ba130
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # RailsCom
2
- Short description and motivation.
2
+ Rails Common engine, with many sugars!
3
3
 
4
4
  ## Installation
5
5
  Add this line to your application's Gemfile:
@@ -17,9 +17,11 @@ Or install it yourself as:
17
17
  ```bash
18
18
  $ gem install rails_com
19
19
  ```
20
- ## Usage
21
- How to use my plugin.
22
-
20
+ ## Features
21
+ * examples: puma, configs etc.
22
+ * rails and ruby core extension;
23
+ * methods deal rails model/controller/routes etc.
24
+ * some helpers, for generator uuid based on time and more;
23
25
 
24
26
  ### View: add link
25
27
  ```erb
@@ -0,0 +1,59 @@
1
+ function listenCheckedIds(name) {
2
+ var checked = 'input[name=' + name + ']';
3
+ var add_ids = [];
4
+ var remove_ids = [];
5
+ var index;
6
+ window.sessionStorage.setItem(name + '_add_ids', []);
7
+ window.sessionStorage.setItem(name + '_remove_ids', []);
8
+
9
+ $(checked).change(function(){
10
+ if (this.checked && this.checked !== this.defaultChecked) {
11
+ add_ids.push(this.value)
12
+ } else if (this.checked && this.checked === this.defaultChecked) {
13
+ index = remove_ids.indexOf(this.value);
14
+ remove_ids.splice(index, 1);
15
+ } else if (!this.checked && this.checked !== this.defaultChecked) {
16
+ remove_ids.push(this.value)
17
+ } else if (!this.checked && this.checked === this.defaultChecked) {
18
+ index = add_ids.indexOf(this.value);
19
+ add_ids.splice(index, 1);
20
+ }
21
+ window.sessionStorage.setItem(name + '_remove_ids', remove_ids);
22
+ window.sessionStorage.setItem(name + '_add_ids', add_ids);
23
+ })
24
+ }
25
+
26
+ function getAddIds(name){
27
+ add_str = window.sessionStorage.getItem(name + '_add_ids');
28
+ return add_str;
29
+ }
30
+
31
+ function getRemoveIds(name){
32
+ remove_str = window.sessionStorage.getItem(name + '_remove_ids');
33
+ return remove_str
34
+ }
35
+
36
+ function toggleAll(source, name) {
37
+ var checkboxes = document.getElementsByName(name);
38
+ var add_ids = [];
39
+ var remove_ids = [];
40
+ var index;
41
+
42
+ for(checkbox of checkboxes) {
43
+ checkbox.checked = source.checked;
44
+ if (checkbox.checked && checkbox.checked !== checkbox.defaultChecked) {
45
+ add_ids.push(checkbox.value)
46
+ } else if (checkbox.checked && checkbox.checked === checkbox.defaultChecked) {
47
+ index = remove_ids.indexOf(checkbox.value);
48
+ remove_ids.splice(index, 1);
49
+ } else if (!checkbox.checked && checkbox.checked !== checkbox.defaultChecked) {
50
+ remove_ids.push(checkbox.value)
51
+ } else if (!checkbox.checked && checkbox.checked === checkbox.defaultChecked) {
52
+ index = add_ids.indexOf(checkbox.value);
53
+ add_ids.splice(index, 1);
54
+ }
55
+ }
56
+
57
+ window.sessionStorage.setItem(name + '_remove_ids', remove_ids);
58
+ window.sessionStorage.setItem(name + '_add_ids', add_ids);
59
+ }
@@ -1,7 +1,10 @@
1
1
  function timeForLocalized(){
2
2
  $('time[data-localized!="true"]').each(function(){
3
- this.textContent = moment.utc(this.textContent).local().format('YYYY-MM-DD HH:mm:ss');
4
- this.dataset['localized'] = 'true'
3
+ if (this.textContent.length > 0) {
4
+ var format = this.dataset['format'] || 'YYYY-MM-DD HH:mm:ss';
5
+ this.textContent = moment.utc(this.textContent).local().format(format);
6
+ this.dataset['localized'] = 'true'
7
+ }
5
8
  })
6
9
  }
7
10
 
@@ -8,46 +8,12 @@ function fetch_xhr_script(url, params){
8
8
  };
9
9
 
10
10
  fetch(url, params).then(function(response) {
11
- return response.text()
11
+ return response.text();
12
12
  }).then(function(text) {
13
13
  var script = document.createElement('script');
14
14
  script.text = text;
15
15
  document.head.appendChild(script).parentNode.removeChild(script);
16
16
  }).catch(function(ex) {
17
- console.log('parsing failed', ex)
17
+ console.log('parsing failed', ex);
18
18
  })
19
- }
20
-
21
- function listenCheckedIds(name) {
22
- var checked = 'input[name="' + name + '"]:checked';
23
- var unchecked = 'input[name="' + name + '"][checked!="checked"]';
24
-
25
- window.add_ids = [];
26
- window.remove_ids = [];
27
- $(checked).change(function(){
28
- if(this.checked){
29
- var index = window.remove_ids.indexOf(this.value);
30
- window.remove_ids.splice(index, 1);
31
- } else {
32
- window.remove_ids.push(this.value)
33
- }
34
- });
35
- $(unchecked).change(function(){
36
- if(this.checked){
37
- window.add_ids.push(this.value)
38
- } else {
39
- var index = window.add_ids.indexOf(this.value);
40
- window.add_ids.splice(index, 1);
41
- }
42
- });
43
- }
44
-
45
- function getAddIds(){
46
- add_str = window.add_ids.join(',');
47
- return add_str;
48
- }
49
-
50
- function getRemoveIds(){
51
- remove_str = window.remove_ids.join(',');
52
- return remove_str
53
- }
19
+ }
@@ -0,0 +1,40 @@
1
+ function sidebarSide1() {
2
+ $('.ui.side').addClass('invisible');
3
+ $('.ui.side .ui.menu').removeClass('accordion');
4
+ $('.ui.side .ui.menu').addClass('icon');
5
+ $('.ui.side .ui.menu .dropdown.icon').remove();
6
+ $('.ui.side .ui.menu .item:not(.header)').addClass('ui dropdown');
7
+ $('.ui.dropdown.item').dropdown({on: 'hover'});
8
+ $('.ui.side .ui.menu .item:not(.header)').removeClass('hidden');
9
+ }
10
+
11
+ function sidebarSide2() {
12
+ $('.ui.side').removeClass('invisible');
13
+ $('.ui.side .ui.menu').addClass('accordion');
14
+ $('.ui.side .ui.menu').removeClass('icon');
15
+ $('.ui.side .ui.menu .item:not(.header)').removeClass('ui dropdown');
16
+ $('.ui.side .ui.menu .dropdown.icon').remove();
17
+ $('.ui.side .ui.menu .title').append('<i class="dropdown icon"></i>');
18
+ $('.ui.accordion').accordion({selector: {trigger: '.title'}});
19
+ $('.ui.side .ui.menu .item:not(.header)').dropdown('destroy');
20
+ }
21
+
22
+ document.addEventListener('turbolinks:load', function(){
23
+
24
+ $('#close_side').click(function() {
25
+ if ($('.ui.side').hasClass('invisible')) {
26
+ window.localStorage.setItem('invisible', 'false');
27
+ sidebarSide2();
28
+ } else {
29
+ window.localStorage.setItem('invisible', 'true');
30
+ sidebarSide1();
31
+ }
32
+ });
33
+
34
+ if (localStorage.getItem('invisible') === 'true') {
35
+ sidebarSide1();
36
+ } else {
37
+ sidebarSide2();
38
+ }
39
+
40
+ });
@@ -7,12 +7,4 @@ class CommonController < ApplicationController
7
7
  end
8
8
  end
9
9
 
10
- def not_found
11
- params.permit!
12
- RailsCom.not_found_logger.info "#{params[:path]}.#{params[:format]}"
13
-
14
- head :not_found
15
- end
16
-
17
-
18
10
  end
@@ -14,8 +14,8 @@ module TheCommonApi
14
14
  def process_errors(model)
15
15
  render json: {
16
16
  errors: model.errors.as_json(full_messages: true),
17
- full_messages: model.errors.full_messages.join(',')
18
- }, status: 500
17
+ full_messages: model.errors.full_messages.join("\n")
18
+ }, status: 200
19
19
  end
20
20
 
21
21
  def wrap_body
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RailsCom::ActiveHelper
2
3
 
3
4
  # active_assert('notice' == 'notice', expected: 'ui info message', unexpected: 'ui negative message')
@@ -1,4 +1,5 @@
1
- module RailsComHelper
1
+ # frozen_string_literal: true
2
+ module RailsCom::AssetsHelper
2
3
 
3
4
  def js_load(filename = nil, root: nil, **options)
4
5
  filename ||= "controllers/#{controller_path}/#{action_name}"
@@ -27,13 +28,4 @@ module RailsComHelper
27
28
  end
28
29
  end
29
30
 
30
- def simple_format_hash(hash_text, options = {})
31
- wrapper_tag = options.fetch(:wrapper_tag, :p)
32
-
33
- hash_text.map do |k, v|
34
- text = k.to_s + ': ' + v.to_s
35
- content_tag(wrapper_tag, text)
36
- end.join("\n\n").html_safe
37
- end
38
-
39
31
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module RailsCom::CommonHelper
3
+
4
+ def simple_format_hash(hash_text, options = {})
5
+ wrapper_tag = options.fetch(:wrapper_tag, :p)
6
+
7
+ hash_text.map do |k, v|
8
+ text = k.to_s + ': ' + v.to_s
9
+ content_tag(wrapper_tag, text)
10
+ end.join("\n\n").html_safe
11
+ end
12
+
13
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module RailsCom::TimeHelper
3
+
4
+ def exact_distance_time(from_time, to_time, options = {})
5
+ result = TimeHelper.exact_distance_time(from_time, to_time)
6
+
7
+ options = {
8
+ scope: :'datetime.prompts'
9
+ }.merge!(options)
10
+
11
+ I18n.with_options locale: options[:locale], scope: options[:scope] do |locale|
12
+ str = ''
13
+ result.each do |k, v|
14
+ if v > 0
15
+ str << v.to_s << locale.t(k)
16
+ end
17
+ end
18
+ str
19
+ end
20
+ end
21
+
22
+ end
@@ -1,27 +1,75 @@
1
1
  module StateMachine
2
2
 
3
- # obj = Model.new
4
- # obj.process_to state: 'xxx'
5
- def process_to(options = {})
6
- if options.size > 1
7
- raise 'Only support one column'
3
+ # to defined next_xxx_states in class
4
+
5
+ # obj.next_to state: 'xxx'
6
+ def next_to(options = {})
7
+ options.each do |column, value|
8
+ if self.class.method_defined? "next_#{column}_states"
9
+ _next_state = self.send("next_#{column}_states").first
10
+ else
11
+ _next_state = next_state(column)
12
+ end
13
+
14
+ if _next_state == value.to_s
15
+ assign_attributes(column => value)
16
+ else
17
+ error_msg = "Next state is wrong, should be #{_next_state}"
18
+ errors.add column, error_msg
19
+ raise ActiveRecord::Rollback, error_msg
20
+ end
8
21
  end
22
+ end
9
23
 
10
- options.each do |k, v|
11
- states = k.to_s.pluralize
12
- states = self.class.send(states)
24
+ def next_to!(options = {})
25
+ self.next_to(options, &block)
26
+ self.save!
27
+ end
13
28
 
14
- i = states[self.send(k)]
15
- n = states.key(i+1)
29
+ def trigger_to(options = {})
30
+ options.each do |column, value|
31
+ if self.class.method_defined? "next_#{column}_states"
32
+ _next_states = self.send "next_#{column}_states"
33
+ else
34
+ _next_states = next_states(column)
35
+ end
16
36
 
17
- if n == v.to_s
18
- assign_attributes(k => v)
19
- save!
37
+ if _next_states.include?(value.to_s)
38
+ assign_attributes(column => value)
20
39
  else
21
- errors.add k, 'Next state is wrong'
22
- raise ActiveRecord::Rollback, 'Next state is wrong'
40
+ error_msg = "Next state is wrong, should be one of #{_next_states.join(', ')}"
41
+ errors.add column, error_msg
42
+ raise ActiveRecord::Rollback, error_msg
23
43
  end
24
44
  end
25
45
  end
26
46
 
47
+ def trigger_to!(options = {})
48
+ self.trigger_to(options, &block)
49
+ self.save!
50
+ end
51
+
52
+ # obj.next_states(:state) do |result|
53
+ # result.reject
54
+ # end
55
+ def next_states(state_name, &block)
56
+ _states = self.class.send(state_name.to_s.pluralize)
57
+ _states = _states.keys
58
+ _state = self.send(state_name)
59
+
60
+ if _state.nil?
61
+ next_index = 0
62
+ else
63
+ i = _states.index(_state)
64
+ next_index = i + 1
65
+ end
66
+ result = _states[next_index..(_states.size - 1)]
67
+
68
+ if block_given?
69
+ yield block.call(result)
70
+ else
71
+ result
72
+ end
73
+ end
74
+
27
75
  end
@@ -1,5 +1,5 @@
1
1
  <div class="ui simple dropdown item">
2
- <i class="translate icon"></i>
2
+ <i class="globe icon"></i>
3
3
  <%= I18n.locale %>
4
4
  <div class="menu">
5
5
  <%= link_to 'EN', { locale: 'en' }, class: 'item' %>
@@ -22,4 +22,10 @@ en:
22
22
  update: 'Updates %{model}'
23
23
  submit: 'Saves %{model}'
24
24
  q:
25
- submit: 'Search'
25
+ submit: 'Search'
26
+ number:
27
+ human:
28
+ storage_units:
29
+ units:
30
+ h: Hours
31
+ m: Min
@@ -0,0 +1,44 @@
1
+ zh:
2
+ datetime:
3
+ distance_in_words:
4
+ half_a_minute: 半分钟
5
+ less_than_x_seconds:
6
+ one: 不到1秒
7
+ other: '不到%{count}秒'
8
+ x_seconds:
9
+ one: 1秒
10
+ other: '%{count}秒'
11
+ less_than_x_minutes:
12
+ one: 不到1分钟
13
+ other: '不到%{count}分钟'
14
+ x_minutes:
15
+ one: 1分钟
16
+ other: '%{count}分钟'
17
+ about_x_hours:
18
+ one: 1小时
19
+ other: '%{count}小时'
20
+ x_days:
21
+ one: 1天
22
+ other: '%{count}天'
23
+ about_x_months:
24
+ one: 1个月
25
+ other: '%{count}个月'
26
+ x_months:
27
+ one: 1个月
28
+ other: '%{count} months'
29
+ about_x_years:
30
+ one: 1年
31
+ other: '%{count} years'
32
+ over_x_years:
33
+ one: '超过1年'
34
+ other: '%{count} 年'
35
+ almost_x_years:
36
+ one: 'almost 1 year'
37
+ other: 'almost %{count} years'
38
+ prompts:
39
+ year: 年
40
+ month: 月
41
+ day: 日
42
+ hour: 小时
43
+ minute: 分钟
44
+ second: 秒
@@ -1,4 +1,13 @@
1
1
  zh:
2
+ errors:
3
+ format: "%{attribute} %{message}"
4
+ messages:
5
+ record_invalid: "验证失败: %{errors}"
6
+ model_invalid: "验证失败: %{errors}"
7
+ required: 必须存在
8
+ blank: 不能为空
9
+ too_short: 长度不够
10
+ taken: 已被占用
2
11
  views:
3
12
  pagination:
4
13
  first: First
data/config/routes.rb CHANGED
@@ -6,7 +6,3 @@ Rails.application.routes.draw do
6
6
  end
7
7
 
8
8
  end
9
-
10
- Rails.application.routes.append do
11
- match '*path' => 'common#not_found', via: :all
12
- end
data/lib/mina/puma.rb CHANGED
@@ -1,5 +1,6 @@
1
- set :puma_cmd, -> { "#{fetch :bundle_prefix} puma -e #{fetch :rails_env}" }
2
- set :pumactl_cmd, -> { "#{fetch :bundle_prefix} pumactl" }
1
+ set :bundle_more_prefix, -> { "BUNDLE_GEMFILE=#{fetch(:current_path) + '/Gemfile'} #{fetch :bundle_prefix}" }
2
+ set :puma_cmd, -> { "#{fetch :bundle_more_prefix} puma -e #{fetch :rails_env}" }
3
+ set :pumactl_cmd, -> { "#{fetch :bundle_more_prefix} pumactl" }
3
4
  set :puma_socket, -> { "#{fetch :current_path}/tmp/pids/puma.pid" }
4
5
 
5
6
  namespace :puma do
@@ -0,0 +1,27 @@
1
+ set :whenever_name, -> { "#{fetch(:domain)}_#{fetch(:rails_env)}" }
2
+
3
+ namespace :whenever do
4
+ desc 'Clear crontab'
5
+ task clear: :remote_environment do
6
+ comment "Clear crontab for #{fetch(:whenever_name)}"
7
+ in_path fetch(:current_path) do
8
+ command "#{fetch(:bundle_bin)} exec whenever --clear-crontab #{fetch(:whenever_name)} --set 'environment=#{fetch(:rails_env)}&path=#{fetch(:current_path)}'"
9
+ end
10
+ end
11
+
12
+ desc 'Update crontab'
13
+ task update: :remote_environment do
14
+ comment "Update crontab for #{fetch(:whenever_name)}"
15
+ in_path fetch(:current_path) do
16
+ command "#{fetch(:bundle_bin)} exec whenever --update-crontab #{fetch(:whenever_name)} --set 'environment=#{fetch(:rails_env)}&path=#{fetch(:current_path)}'"
17
+ end
18
+ end
19
+
20
+ desc 'Write crontab'
21
+ task write: :remote_environment do
22
+ comment "Write crontab for #{fetch(:whenever_name)}"
23
+ in_path fetch(:current_path) do
24
+ command "#{fetch(:bundle_bin)} exec whenever --write-crontab #{fetch(:whenever_name)} --set 'environment=#{fetch(:rails_env)}&path=#{fetch(:current_path)}'"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ module RailsCom
2
+ include ActiveSupport::Configurable
3
+ config_accessor :access_denied_method, :default_admin_emails
4
+
5
+ configure do |config|
6
+ config.ignore_controllers = [
7
+ 'rails/welcome'
8
+ ]
9
+ end
10
+
11
+ end
@@ -0,0 +1,54 @@
1
+ class Array
2
+
3
+ # arr = [1, 2, 3]
4
+ # arr.rjust! 5, nil
5
+ # => [1, 2, 3, nil, nil]
6
+ def rjust!(n, x)
7
+ return self if n < length
8
+ insert(0, *Array.new([0, n-length].max, x))
9
+ end
10
+
11
+ # arr = [1, 2, 3]
12
+ # arr.ljust! 5, nil
13
+ # => [nil, nil, 1, 2, 3]
14
+ def ljust!(n, x)
15
+ return self if n < length
16
+ fill(x, length...n)
17
+ end
18
+
19
+ # arr = [1, 2, 3]
20
+ # arr.mjust!(5, nil)
21
+ # => [1, 2, nil, nil, 3]
22
+ def mjust!(n, x)
23
+ return self if n < length
24
+ insert (length / 2.0).ceil, *Array.new(n - length, x)
25
+ end
26
+
27
+ # raw_data = [
28
+ # { a: 1 },
29
+ # { a: 2 },
30
+ # { b: 2 }
31
+ # ]
32
+ # raw_data.to_combined_hash
33
+ # => { a: [1, 2], b: 2 }
34
+ def to_combined_hash
35
+ self.reduce({}) do |memo, index|
36
+ memo.merge(index) { |_, value, default| [value, default] }
37
+ end
38
+ end
39
+
40
+ # raw_data = [
41
+ # [:a, 1],
42
+ # [:a, 2],
43
+ # [:b, 2]
44
+ # ]
45
+ # raw_data.to_combined_h
46
+ # => { a: [1, 2], b: 2 }
47
+ # todo nested array bug
48
+ def to_combined_h
49
+ hash = {}
50
+ self.each { |x, y| hash[x] = hash[x] ? Array(hash[x]) << y : y }
51
+ hash
52
+ end
53
+
54
+ end
@@ -13,7 +13,6 @@ module RailsCom::ModelHelper
13
13
  generator.invoke_all
14
14
  end
15
15
 
16
-
17
16
  def column_attributes
18
17
  columns.map do |column|
19
18
  [
@@ -27,7 +26,6 @@ module RailsCom::ModelHelper
27
26
  end
28
27
  end
29
28
 
30
-
31
29
  def print_table(with_column: false)
32
30
  columns.each do |column|
33
31
  info = with_column ? '# t.column' : '# '
@@ -48,7 +46,60 @@ module RailsCom::ModelHelper
48
46
  nil
49
47
  end
50
48
 
51
- end
49
+ def sql_table(except: [], only: [], pure: true)
50
+ if only.size > 0
51
+ _columns = columns.select { |column| only.include?(column.name) }
52
+ else
53
+ _columns = columns.reject { |column| except.include?(column.name) }
54
+ end
55
+
56
+ if pure
57
+ sql = ""
58
+ else
59
+ sql = "CREATE TABLE `#{self.table_name}` (\n"
60
+ end
61
+
62
+ _columns.each do |column|
63
+ sql << " `#{column.name}` #{column.sql_type}"
64
+ sql << " COLLATE #{column.collation}" if column.collation
65
+ sql << " NOT NULL" unless column.null
66
+ if column.default
67
+ sql << " DEFAULT '#{column.default}',\n"
68
+ elsif column.default.nil? && column.null
69
+ sql << " DEFAULT NULL,\n"
70
+ else
71
+ sql << ",\n"
72
+ end
73
+ end
74
+
75
+ sql << " PRIMARY KEY (`#{self.primary_key}`)"
52
76
 
77
+ _indexes = connection.indexes(self.table_name).reject { |index| (index.columns & _columns.map { |col| col.name }).blank? }
78
+ if _indexes.present?
79
+ sql << ",\n"
80
+ else
81
+ sql << "\n"
82
+ end
83
+ _indexes.each_with_index do |obj, index|
84
+ sql << " KEY `#{obj.name}` ("
85
+ sql << obj.columns.map { |col| "`#{col}`" }.join(',')
86
+
87
+ if index + 1 == _indexes.size
88
+ sql << ")\n"
89
+ else
90
+ sql << "),\n"
91
+ end
92
+ end
93
+
94
+ if pure
95
+ sql
96
+ else
97
+ sql << ")"
98
+ end
99
+ end
53
100
 
54
- ActiveRecord::Base.extend RailsCom::ModelHelper
101
+ end
102
+
103
+ ActiveSupport.on_load :active_record do
104
+ extend RailsCom::ModelHelper
105
+ end