blade-setting 0.1.8 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/bin/bs CHANGED
@@ -1,33 +1,93 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require_relative '../lib/blade/setting'
4
3
 
4
+ SCRIPT_RAILS = File.join('bin', 'rails')
5
5
  require 'tty-prompt'
6
6
  prompt = TTY::Prompt.new
7
- result = prompt.collect do
8
- key(:setting_path).ask('The generated config file path', default: '/app/settings')
7
+ prompt.warn('Load Rails App Env now...you may need to wait a seconds')
9
8
 
10
- setting_choices = %w(redis sentry influxdb scout_apm send_cloud elastic_search wechat carrierwave)
9
+ def in_rails_application?
10
+ File.exists?(SCRIPT_RAILS)
11
+ end
11
12
 
12
- prompt.say('Please select the config file you want to generate,
13
- (Use arrow keys, press Space to select and Enter to finish, and letter keys to filter)')
14
- key(:configs).multi_select('check configs',
15
- setting_choices, filter: true)
13
+ def ok
14
+ prompt = TTY::Prompt.new
15
+ prompt.ok("generate complete ! check files now")
16
+ exit(0);
17
+ end
18
+
19
+ if in_rails_application?
20
+ app_path = Dir.pwd + '/config/environment'
21
+ require app_path
22
+ prompt.ok('Load Rails Application ENV Success!')
23
+ else
24
+ prompt.error('You are not in Rails app root,please enter your rails app directory and run the cli tool')
25
+ exit(0);
26
+ end
16
27
 
17
- key(:yml_path).ask('The generated yml path', default: '/environments')
28
+ require_relative '../lib/blade/setting'
18
29
 
19
- key(:extra_yml_path).ask('Other environment? (Input words like sit,dit,prod)', default: 'dev,sit,dit,prod') do |q|
20
- q.convert -> (input) {input.split(/,\s*/)}
30
+ menu_result = prompt.collect do
31
+ key(:menu).select('select the menu you want to do') do |menu|
32
+ menu.choice "Generate yml and setting logic files", 1
33
+ menu.choice "Generate Model's crud scaffold", 2
34
+ menu.choice "Add graphql base file to your project", 3
35
+ menu.choice "Add Base File for project [response.rb,application.json.jbuilder, application.helper, base_model_concern]", 4
21
36
  end
22
37
  end
23
38
 
24
- prompt.ok('config complete')
25
- prompt.warn("generating files ...plz don't quit")
39
+ case menu_result[:menu]
40
+ when 1
41
+ result = prompt.collect do
42
+ key(:setting_path).ask('The generated config file path', default: '/app/settings')
43
+
44
+ setting_choices = %w(redis sentry database influxdb scout_apm send_cloud elastic_search wechat carrierwave)
45
+
46
+ prompt.say('Please select the config file you want to generate,
47
+ (Use arrow keys, press Space to select and Enter to finish, and letter keys to filter)')
48
+ key(:configs).multi_select('check configs',
49
+ setting_choices, filter: true)
50
+
51
+ key(:yml_path).ask('The generated yml path', default: '/environments')
52
+
53
+ key(:extra_yml_path).ask('Other environment? (Input words like sit,dit,prod)', default: 'dev,sit,dit,prod') do |q|
54
+ q.convert -> (input) {input.split(/,\s*/)}
55
+ end
56
+ end
57
+
58
+ prompt.ok('config complete')
59
+ prompt.warn("generating files ...plz don't quit")
26
60
  #生成setting logic
27
- Blade::BladeSetting.generate_setting_logic(result[:setting_path], result[:configs])
61
+ Blade::BladeSetting.generate_setting_logic(result[:setting_path], result[:configs])
62
+
63
+ prompt.warn('generating yml files ...')
64
+ Blade::BladeSetting.generate_setting_yml(result[:yml_path], result[:extra_yml_path], result[:configs])
65
+
66
+ prompt.ok("generate complete ! check files now")
67
+
68
+ when 2
69
+ model_result = prompt.collect do
70
+ key(:model_name).ask('enter the model name')
71
+ key(:namespace).ask('enter the controller namespace',default:'api')
72
+ end
73
+ ActiveRecord::Base.connection
74
+ model = Blade::BladeSetting.get_model(model_result[:model_name].classify)
75
+ if (model.blank?)
76
+ prompt.error("Model doesn't exist")
77
+ exit(0);
78
+ end
79
+ prompt.warn("generating files ...please don't quit")
80
+ Blade::BladeSetting.generate_model_template(model)
81
+ Blade::BladeSetting.generate_crud(model,model_result[:namespace])
82
+ ok();
83
+
84
+ when 3
85
+
86
+ when 4
87
+ Blade::BladeSetting.generate_base_files
88
+ ok();
89
+
90
+ end
28
91
 
29
- prompt.warn('generating yml files ...')
30
- Blade::BladeSetting.generate_setting_yml(result[:yml_path],result[:extra_yml_path], result[:configs])
31
92
 
32
- prompt.ok("generate complete ! check files now")
33
93
 
@@ -23,11 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib"]
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.11"
26
+ spec.add_development_dependency "bundler", ">= 1.1"
27
27
  spec.add_development_dependency "rake", "~> 10.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
- spec.add_dependency "rainbow" ,"~>2.1.0"
30
29
  spec.add_dependency "tty-prompt", "~>0"
31
- spec.add_dependency "activesupport", '~> 5.0'
32
- spec.add_dependency "fileutils","~> 0.7.2"
33
30
  end
@@ -1,23 +1,26 @@
1
- require "uri"
2
- require "net/http"
3
- require "json"
4
- require "rainbow/ext/string"
5
- require "active_support/all"
6
- require 'fileutils'
7
- require 'blade/setting/yml_template'
1
+ require_relative '../blade/setting/yml_template'
2
+ require_relative '../blade/setting/model_template'
3
+ require_relative '../blade/setting/controller_template'
4
+ require_relative '../blade/setting/base_template'
5
+ require 'rails/generators'
8
6
  module Blade
9
7
 
10
8
  class BladeSetting
11
9
 
12
10
  class << self
13
11
 
12
+
13
+ # if in_rails_application? || in_rails_application_subdirectory?
14
+ # exit(0)
15
+ # else
16
+ # exit(1)
17
+ # end
18
+
14
19
  def generate_setting_logic(setting_path, configs = [])
15
20
 
16
21
  configs.each do |config|
17
22
 
18
23
  path = Dir.pwd
19
- p path + setting_path
20
-
21
24
  unless Dir.exist?(path + setting_path)
22
25
  FileUtils.mkdir_p path + setting_path
23
26
  end
@@ -34,11 +37,8 @@ end
34
37
  end
35
38
 
36
39
  def generate_setting_yml(yml_base_path, extra_path, configs = [])
37
-
38
40
  all_environment_paths = extra_path
39
-
40
41
  all_environment_paths.each do |env_path|
41
-
42
42
  path = Dir.pwd
43
43
  unless Dir.exist?(path + yml_base_path + '/' + env_path)
44
44
  FileUtils.mkdir_p path + yml_base_path + '/' + env_path + '/' + 'config'
@@ -49,7 +49,123 @@ end
49
49
  file.write yml_file
50
50
  end
51
51
  end
52
+ end
53
+
54
+ def generate_model_template(model_class)
55
+ model_file = Blade::Setting::ModelTemplate.model_template(model_class)
56
+ path = Dir.pwd + "/app/models/" + model_class.name.downcase + ".rb"
57
+ gt = Blade::Setting::ControllerTemplate::InstallGenerator.new
58
+ file = nil
59
+ file_path = Rails.root.join('app','models',"#{model_class.name.downcase}.rb")
60
+ # if File.exist?(path)
61
+ # file = File.open(path, "w")
62
+ # else
63
+ # file = File.new(path, "w")
64
+ # end
65
+ # file.write model_file;
66
+ gt.create_view_file(file_path,model_file)
67
+ end
68
+
69
+ def generate_crud(model_class, namespace)
70
+
71
+ model = model_class.name
72
+ arg1 = model_class.name.downcase
73
+ args = arg1.pluralize
74
+
75
+ #generate routes
76
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.add_routes(args, namespace)
77
+
78
+ #generate controller
79
+ con_path = Rails.root.join('app', 'controllers', namespace, "#{args}_controller.rb")
80
+ con_file = Blade::Setting::ControllerTemplate::InstallGenerator.controller_tmp(model_class, namespace);
81
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(con_path, con_file)
82
+
83
+
84
+ #generate views
85
+ index_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'index.json.jbuilder')
86
+ common_view_path = Rails.root.join('app', 'views', namespace, 'common', "_#{arg1}.json.jbuilder")
87
+ update_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'update.json.jbuilder')
88
+ create_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'create.json.jbuilder')
89
+ delete_view_path = Rails.root.join('app', 'views', namespace, args.to_s, 'destroy.json.jbuilder')
90
+
91
+ index_content = <<-File
92
+
93
+ json.#{args} do
94
+ if @#{args}.present?
95
+ render_json_array_partial(json,@#{args},'common/#{arg1}',:#{arg1})
96
+ else
97
+ {}
98
+ end
99
+ end
100
+ File
101
+ common_view_content = <<-File
102
+ if #{arg1}.present?
103
+ render_json_attrs(json, #{arg1})
104
+ else
105
+ json.#{arg1} {}
106
+ end
107
+
108
+ File
109
+
110
+ create_view_content = <<-File
111
+ if @#{arg1}.present?
112
+ json.#{arg1} do
113
+ render_json_attrs(json, @#{arg1})
114
+ end
115
+ else
116
+ json.#{arg1} {}
117
+ end
118
+ File
119
+ #
120
+ update_view_content = <<-File
121
+ json.#{arg1} do
122
+ if @#{arg1}.present?
123
+ render_json_attrs(json,@#{arg1})
124
+ else
125
+ {}
126
+ end
127
+ end
128
+
129
+ File
130
+
131
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(index_view_path, index_content)
132
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(create_view_path, create_view_content)
133
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(update_view_path, update_view_content)
134
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(common_view_path, common_view_content)
135
+ Blade::Setting::ControllerTemplate::InstallGenerator.new.create_view_file(delete_view_path, '')
136
+
137
+ end
138
+
139
+ def generate_base_files
140
+
141
+ generator = Blade::Setting::ControllerTemplate::InstallGenerator.new
142
+
143
+ application_helper = Blade::Setting::BaseTemplate::APPLICATION_HELPER
144
+ application_builder = Blade::Setting::BaseTemplate::APPLICATION_JSON_BUILDER
145
+ base_model_concern = Blade::Setting::BaseTemplate::BASE_MODEL_CONCERN
146
+ response = Blade::Setting::BaseTemplate::RESPONSE
147
+ response_json = Blade::Setting::BaseTemplate::RESPONSE_JSON
148
+
149
+ application_helper_path = Rails.root.join('app', 'helpers','application_helper.rb')
150
+ application_builder_path = Rails.root.join('app', 'views', 'layouts' ,'application.json.jbuilder')
151
+ response_path = Rails.root.join('app', 'models' ,'response.rb')
152
+ base_model_concern_path = Rails.root.join('app', 'models', 'concerns', 'base_model_concern.rb')
153
+ response_json_path = Rails.root.join('app', 'views', 'common', '_response_status.json.jbuilder')
154
+
155
+ generator.create_view_file(application_builder_path, application_builder)
156
+ generator.create_view_file(application_helper_path, application_helper)
157
+ generator.create_view_file(response_path, response)
158
+ generator.create_view_file(base_model_concern_path, base_model_concern)
159
+ generator.create_view_file(response_json_path, response_json)
160
+ end
161
+
162
+ def generate_custom_yml(name)
163
+ gt = Blade::Setting::ControllerTemplate::InstallGenerator.new
164
+ end
165
+
52
166
 
167
+ def get_model(name)
168
+ ActiveSupport::Dependencies.constantize(name.classify)
53
169
  end
54
170
 
55
171
  end
@@ -0,0 +1,882 @@
1
+ module Blade
2
+ module Setting
3
+
4
+ module BaseTemplate
5
+
6
+
7
+ BASE_MODEL_CONCERN = <<-File
8
+ module BaseModelConcern
9
+ extend ActiveSupport::Concern
10
+
11
+ def self.get_model(model_name)
12
+ ActiveSupport::Dependencies.constantize(model_name.classify)
13
+ end
14
+
15
+ def self.params_blank?(params)
16
+ !params.select {|_k, v| v.blank?}.empty?
17
+ end
18
+
19
+ module ClassMethods
20
+ def get_model(model_name)
21
+ ActiveSupport::Dependencies.constantize(model_name.classify)
22
+ end
23
+
24
+ def permit_params
25
+ name = self.model_name.singular
26
+ p = "("
27
+ self.columns.each {|c|
28
+ if (c.name != 'id')
29
+ p += ":#{'#{c.name}'},"
30
+ end}
31
+ p += ")"
32
+ puts p
33
+ return "ok"
34
+ end
35
+
36
+ def api_params
37
+ name = self.model_name.singular
38
+ self.columns.each {|c| puts "param :#{'#{' "' + name + '[' + c.name + ']" ' }'},String,desc: '#{'#{c.comment}'}' "}
39
+ return "ok"
40
+ end
41
+
42
+ # 获取字段的备注信息
43
+ # 使用 User.column_comments => hash
44
+ def column_comments
45
+ column_comments = self.connection.retrieve_column_comments(self.table_name)
46
+ column_comments
47
+ end
48
+
49
+ # 使用 User.column_comment('username') => '用户名'
50
+ def column_comment(column_name)
51
+ column_name = column_name.to_s
52
+ return '' unless self.column_names.include?(column_name)
53
+
54
+ column_comments = self.connection.retrieve_column_comments(self.table_name)
55
+ comment = column_comments[column_name.to_sym]
56
+ comment
57
+ end
58
+
59
+ # 辅助方法 将传递进来的true false 转换为 是 否
60
+ def true_change(value = '')
61
+ temp_value = value
62
+ case value
63
+ when true, 'true'
64
+ temp_value = '是'
65
+ when false, 'false'
66
+ temp_value = '否'
67
+ when 'un_pass'
68
+ temp_value = '不通过'
69
+ when 'pass'
70
+ temp_value = '通过'
71
+ when 'success'
72
+ temp_value = '成功'
73
+ when 'fail'
74
+ temp_value = '失败'
75
+ when 'change'
76
+ temp_value = '课程确认'
77
+ when 'modify'
78
+ temp_value = '未通过'
79
+ when 'file'
80
+ temp_value = '失败,需补材料'
81
+ when 'internet'
82
+ temp_value = '在线申请'
83
+ when 'paper'
84
+ temp_value = '邮件申请'
85
+ when 'other'
86
+ temp_value = '线下支付'
87
+ when 'liuyangbao'
88
+ temp_value = '留洋宝支付'
89
+ when 'provide_credit_card'
90
+ temp_value = '提供信用卡信息'
91
+ when 'provided', 'provided_cer'
92
+ temp_value = '已提供'
93
+ when 'un_provided'
94
+ temp_value = '未提供'
95
+ when '是'
96
+ temp_value = true
97
+ when '否'
98
+ temp_value = false
99
+ when 'institutional_feedback'
100
+ temp_value = '院校反馈'
101
+ when 'refusal'
102
+ temp_value = '院校拒录取'
103
+ when 'offer'
104
+ temp_value = '成功'
105
+ when 'success_enter'
106
+ temp_value = '付费注册无条件'
107
+ when 'fail_enter'
108
+ temp_value = '付费注册有条件'
109
+ end
110
+
111
+ temp_value
112
+ end
113
+
114
+ # 获取七牛上传文件的凭证
115
+ def get_upload_token
116
+ put_policy = Qiniu::Auth::PutPolicy.new(
117
+ CarrierwaveSetting.qiniu.bucket, # 存储空间
118
+ nil, # 最终资源名,可省略,即缺省为“创建”语义
119
+ 1800, # 相对有效期,可省略,缺省为3600秒后 uptoken 过期
120
+ (Time.now + 30.minutes).to_i # 绝对有效期,可省略,指明 uptoken 过期期限(绝对值),通常用于调试,这里表示半小时
121
+ )
122
+
123
+ uptoken = Qiniu::Auth.generate_uptoken(put_policy) #生成凭证
124
+ bucket_domain = CarrierwaveSetting.qiniu.bucket_domain #存储空间名
125
+
126
+ return uptoken, bucket_domain
127
+ end
128
+
129
+ def es_find_by_id(id)
130
+ $elasticsearch_client.perform_request('GET', "#{'#{self.name.underscore.pluralize}/#{self.name}/#{id}'}")
131
+ end
132
+
133
+
134
+ def search_by_params(options = {})
135
+ result = self.all
136
+ if options.present?
137
+ keys = options.keys
138
+ keys.delete(:page)
139
+ keys.delete(:per)
140
+ keys.each do |key|
141
+ value = options[key]
142
+ next unless value.present? || !value.to_s.empty?
143
+ if key == :order || key == 'order'
144
+ if value.is_a?(Array)
145
+ value.each do |v|
146
+ orders = v.split(' ')
147
+ result = if orders.length == 2
148
+ result.order("#{'#{orders[0]}'} #{'#{orders[1].upcase}'}")
149
+ else
150
+ result.order(value)
151
+ end
152
+ end
153
+ else
154
+ orders = value.split(' ')
155
+ result = if orders.length == 2
156
+ result.order("#{'#{orders[0]}'} #{'#{orders[1].upcase}'}")
157
+ else
158
+ result.order(value)
159
+ end
160
+ end
161
+ elsif key.to_s.include?('like_')
162
+ query = ''
163
+ query_value = {}
164
+ attr_key = key.to_s.gsub('like_', '')
165
+ if attr_key.include?('.')
166
+ ref_table = attr_key.split('.')[0]
167
+ ref_key = attr_key.split('.')[1]
168
+
169
+ if value.is_a?(Array)
170
+ value.each_with_index do |v, i|
171
+ query += "upper(#{'#{attr_key}'}) like :value#{'#{i}'} "
172
+ query += 'or ' if i != value.length - 1
173
+ query_value.merge!({"value#{'#{i}'}": "%#{'#{v.upcase}'}%"})
174
+ end
175
+ result = result.where(query, query_value)
176
+ else
177
+ result = result.where("upper(#{'#{attr_key}'}) like ?", "%#{'#{value.upcase}'}%")
178
+ end
179
+ else
180
+
181
+ if value.is_a?(Array)
182
+ value.each_with_index do |v, i|
183
+ query += "#{'#{self.name.tableize}'}.#{'#{attr_key}'} like :value#{'#{i}'} "
184
+ query += 'or ' if i != value.length - 1
185
+ query_value.merge!({"value#{'#{i}'}": "%#{'#{v.upcase}'}%"})
186
+ end
187
+ result = result.where(query, query_value)
188
+ else
189
+ result = result.where("upper(#{'#{self.name.tableize}'}.#{'#{attr_key}'}) like ?", "%#{'#{value.upcase}'}%") if self.attribute_names.include?(attr_key)
190
+ end
191
+ end
192
+
193
+ # or || 兼容 'students.creator_id'的情况发生 可能传递多个,超过两个
194
+ elsif key.to_s =~ /^or_/
195
+ attr_key = key.to_s.gsub('or_', '')
196
+ values = value.split(' ')
197
+
198
+ if attr_key.include?('.')
199
+ search_key = "#{'#{attr_key}'}" if value.present?
200
+ else
201
+ search_key = "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key) && value.present?
202
+ end
203
+
204
+ query_string = ''
205
+ values.each_with_index do |v, i|
206
+ query_string += "#{'#{search_key}'} = '#{'#{values[i]}'}' or "
207
+ end
208
+ query_string.chomp!(' or ')
209
+
210
+ result = result.where(query_string)
211
+
212
+ # or一个value同时搜多个参数
213
+ elsif key.to_s.include?('&or&')
214
+ # 这边的需求是搜索学校、代理、学生等的拼音名 所以需要同时搜name和name_pinyin 暂时默认是直接需要like的
215
+ # 格式: 'schools.name&or&schools.full_name'
216
+ attr_keys = key.to_s.split('&or&')
217
+ if value.present?
218
+ # query_string = ''
219
+ query_hash = {value: "%#{'#{value.upcase}'}%"}
220
+ query_string = attr_keys.map.with_index do |attr_key, i|
221
+ convert_key = if attr_key.include?('.')
222
+ attr_key
223
+ else
224
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
225
+ end
226
+ convert_key_arr = convert_key.split('.')
227
+ # 用self的话会有问题
228
+ key_type = convert_key_arr.first.classify.constantize.type_for_attribute(convert_key_arr.last).type.to_s.classify
229
+ key_type == String.name ? "upper(#{'#{convert_key}'}) like :value or " : "#{'#{convert_key}'} = :value or "
230
+ end.flatten.join[0..-5]
231
+ result = result.where(query_string, query_hash)
232
+ end
233
+ elsif key.to_s =~ /^compare_/
234
+ attr_key = key.to_s.gsub(/^compare_/, '')
235
+ if value.present?
236
+ query_hash = {}
237
+ query_string = ""
238
+ if attr_key =~ /^lt_/
239
+ attr_key.gsub!(/^lt_/, '')
240
+ convert_key = if attr_key.include?('.')
241
+ attr_key
242
+ else
243
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
244
+ end
245
+ query_hash = {value: "#{'#{value.to_d}'}"}
246
+ query_string = "#{'#{convert_key}'} <= :value "
247
+ elsif attr_key =~ /^bt_/
248
+ attr_key.gsub!(/^bt_/, '')
249
+ convert_key = if attr_key.include?('.')
250
+ attr_key
251
+ else
252
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
253
+ end
254
+ query_hash = {min: "#{'#{value.split(' ')[0]}'}", max: "#{'#{value.split(' ')[1]}'}"}
255
+ query_string = "#{'#{convert_key}'} >= :min and #{'#{convert_key}'} <= :max "
256
+ elsif attr_key =~ /^gt_/
257
+ attr_key.gsub!(/^gt_/, '')
258
+ convert_key = if attr_key.include?('.')
259
+ attr_key
260
+ else
261
+ "#{'#{self.name.tableize}'}.#{'#{attr_key}'}" if self.attribute_names.include?(attr_key)
262
+ end
263
+ query_hash = {value: "#{'#{value.to_d}'}"}
264
+ query_string = "#{'#{convert_key}'} >= :value "
265
+ end
266
+ result = result.where(query_string, query_hash)
267
+ end
268
+ #between
269
+ elsif key.to_s.include?('between_')
270
+ attr_key = key.to_s.gsub('between_', '')
271
+ front, back = value.split(',')
272
+ if attr_key.include?('.')
273
+ result = result.between_fields("#{'#{attr_key}'}", front, back) if value.present? && value.split(',').length == 2
274
+ else
275
+ puts "betewwen #{'#{front}'} #{'#{back}'}"
276
+ result = result.between_fields("#{'#{self.name.tableize}'}.#{'#{attr_key}'}", front, back) if self.attribute_names.include?(attr_key) && value.present? && value.split(',').length == 2
277
+ end
278
+ elsif key.to_s.include?('array_column_')
279
+ attr_key = key.to_s.gsub('array_column_', '')
280
+ result = result.where("#{'#{attr_key}'} && ARRAY[?]::varchar[]", value)
281
+ elsif key.to_s.include?('not_')
282
+ attr_key = key.to_s.gsub('not_', '')
283
+ result = result.where.not("#{'#{attr_key}'} = ?", "#{'#{value}'}")
284
+ else
285
+ key = key.to_s.remove('between_').remove('like_').remove('not_')
286
+ if key.include?('.')
287
+ result = result.where(key.to_sym => value)
288
+ else
289
+ result = result.where("#{'#{self.name.tableize}'}.#{'#{key}'}".to_sym => value) if self.attribute_names.include?(key)
290
+ end
291
+ end
292
+ end
293
+ end
294
+ result
295
+ end
296
+
297
+ def resources_search_by_params(resources, options = {})
298
+ result = resources
299
+ if options.present?
300
+ keys = options.keys
301
+ keys.delete(:page)
302
+ keys.delete(:per)
303
+ keys.each do |key|
304
+ value = options[key]
305
+ next unless value.present? || !value.to_s.empty?
306
+ if key == :order || key == 'order'
307
+ orders = value.split(' ')
308
+
309
+ result = if orders.length == 2
310
+ result.order(orders[0].to_sym => orders[1].to_sym)
311
+ else
312
+ result.order(value)
313
+ end
314
+ else
315
+ result = result.where(key.to_sym => value) if result.model.instance_methods.include?(key) || result.model.attribute_names.include?(key.to_s)
316
+ if key.to_s.include?('like_')
317
+ attr_key = key.to_s.gsub('like_', '')
318
+ if attr_key.include?('.')
319
+ result = result.where("#{'#{attr_key}'} like ?", "%#{'#{value}'}%")
320
+ else
321
+ result = result.where("#{'#{result.model.name.tableize}'}.#{'#{attr_key}'} like ?", "%#{'#{value}'}%") if result.model.attribute_names.include?(attr_key)
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
327
+ result
328
+ end
329
+
330
+ def search_by_hash(args, result_objects = nil)
331
+ result = result_objects.present? ? result_objects : self.all
332
+
333
+ if args.present?
334
+ args.each_key do |key|
335
+ value = args[key]
336
+
337
+ next unless value.present? || !value.to_s.empty?
338
+
339
+ result = result.where("#{'#{self.name.tableize}'}.#{'#{key}'} like ?", "%#{'#{args[key]}'}%") if self.attribute_names.include?(key)
340
+ end
341
+ end
342
+
343
+ result
344
+ end
345
+
346
+ def validate_present?(params)
347
+ params.select(&:present?).empty?
348
+ end
349
+
350
+ def validate_blank?(params)
351
+ return true if params.blank?
352
+ !params.select(&:blank?).empty?
353
+ end
354
+
355
+ def validate_all_present?(*args)
356
+ args.select(&:blank?).empty?
357
+ end
358
+
359
+ def validate_all_blank?(*args)
360
+ return true if args.blank?
361
+ args.select(&:present?).empty?
362
+ end
363
+
364
+ def exist_resource(resource_id)
365
+ return nil if resource_id.blank?
366
+
367
+ self.find_by_id(resource_id)
368
+ end
369
+
370
+ # 为简单的对象保存记录
371
+ # 作者 liangyuzhe 20161225
372
+ def save_values_for_object(options)
373
+ record = nil
374
+ response = Response.rescue do |_res|
375
+ column_sym = (self.columns.map(&:name) - %w(id deleted_at created_at updated_at)).map(&:to_sym)
376
+ hash = {}
377
+ column_sym.each do |c|
378
+ hash.merge!(c => options[c])
379
+ end
380
+ record = self.create!(hash)
381
+ end
382
+ [response, record]
383
+ end
384
+
385
+ # postgresql查询jsonb数据方法
386
+ # params white_list String Array
387
+ # params params ActionController::Parameters
388
+ # params jsonb_column_name string
389
+ # 作者 liangyuzhe 20170108
390
+ #
391
+ def search_by_action_controller_params_for_jsonb(params, white_list, column_name)
392
+ if white_list.present?
393
+ if white_list.is_a? String
394
+ permitted = params.permit(white_list)
395
+ elsif white_list.is_a? Array
396
+ permitted = {}
397
+ white_list.each {|w| permitted.merge!(params.permit(w)) if w.is_a? String}
398
+ end
399
+ end
400
+ if permitted.present?
401
+ find_result(permitted.to_json, column_name)
402
+ else
403
+ self.all
404
+ end
405
+ rescue => e
406
+ yloge e, '传入的数据有问题'
407
+ end
408
+
409
+ # 得到数据方法
410
+ def find_result(permitted, column_name)
411
+ query = nil
412
+ self.columns.map(&:name).each do |c|
413
+ if column_name == c
414
+ query = self.where("#{'#{column_name}'} @> :permitted", permitted: permitted)
415
+ end
416
+ end
417
+ query
418
+ rescue => e
419
+ yloge e, '传入的数据有问题'
420
+ end
421
+
422
+
423
+ def hash_keys_to_symbol(hash)
424
+ {}.tap do |h|
425
+ hash.each {|key, value| h[key.to_sym] = map_value(value)}
426
+ end
427
+ end
428
+ end
429
+
430
+ # 为简单的对象更新记录
431
+ # 作者 liangyuzhe 20161225
432
+ def update_values_for_object(options)
433
+ record = nil
434
+ response = Response.rescue do |_res|
435
+ column_sym = (self.class.columns.map(&:name) - %w(id deleted_at created_at updated_at)).map(&:to_sym)
436
+ hash = {}
437
+ column_sym.each do |c|
438
+ hash.merge!(c => options[c]) if options[c].present?
439
+ end
440
+ record = self.update!(hash)
441
+ end
442
+ [response, record]
443
+ end
444
+
445
+ #构造查询条件
446
+ def self.build_search(options = {})
447
+ if options.present?
448
+ search_string = "where "
449
+ keys = options.keys
450
+ keys.each do |key|
451
+ value = options[key]
452
+ Rails.logger.info ">>>> build_search key: #{'#{key.to_s}'}"
453
+ Rails.logger.info ">>>> build_search value: #{'#{value.to_s}'}"
454
+
455
+ next unless (value.present? || !value.to_s.empty?) and value != "''" and !value.blank?
456
+ #模糊查询
457
+ if key.to_s.include?('like_')
458
+ attr_key = key.to_s.gsub('like_', '')
459
+ str = "#{'#{attr_key}'} like '%#{'#{value}'}%'"
460
+
461
+ #否定查询
462
+ elsif key.to_s.include?('no_')
463
+ attr_key = key.to_s.gsub('no_', '')
464
+ if attr_key == 'academic_category'
465
+ str = "#{'#{attr_key}'} != '#{'#{value.upcase}'}'"
466
+ else
467
+ str = "#{'#{attr_key}'} not like '%#{'#{value}'}%'"
468
+ end
469
+
470
+ #按日期区间查询
471
+ elsif key.to_s.include?('between_')
472
+ attr_key = key.to_s.gsub('between_', '')
473
+ date_array = value.split(',').collect {|item| item.tr('/', '-')}
474
+ str = ''
475
+ if date_array.size > 1
476
+ str = "#{'#{attr_key}'} between '#{'#{date_array[0]}'}' and '#{'#{date_array[1]}'}'"
477
+ elsif value[0].blank?
478
+ str = "#{'#{attr_key}'} <= '#{'#{date_array[0]}'}'"
479
+ elsif value[-1].blank?
480
+ str = "#{'#{attr_key}'} >= '#{'#{date_array[0]}'}'"
481
+ end
482
+
483
+ # #由于数据存在异常 用于特定的按月查询
484
+ # elsif key.to_s.include?('special_')
485
+ # attr_key = key.to_s.gsub('special_', '')
486
+ # begin_month = value.split(' ')[0]
487
+ # end_month = value.split(' ')[1]
488
+ # str = "(#{'#{attr_key}'} between '#{'#{begin_month}'}' and '#{'#{end_month}'}' or in_account_time_month between '#{'#{begin_month}'}' and '#{'#{end_month}'}')"
489
+
490
+ #由于数据存在异常 用于特定的按月查询
491
+ elsif key.to_s.include?('special_')
492
+ attr_key = key.to_s.gsub('special_', '')
493
+ date_array = value.split.collect {|item| item.tr('/', '-')}
494
+ str = ''
495
+ if date_array.size > 1
496
+ str = "(#{'#{attr_key}'} between '#{'#{date_array[0]}'}' and '#{'#{date_array[1]}'}' or in_account_time_month between '#{'#{date_array[0]}'}' and '#{'#{date_array[1]}'}')"
497
+ elsif value[0].blank?
498
+ str = "(#{'#{attr_key}'} <= '#{'#{date_array[0]}'}' or in_account_time_month <= '#{'#{date_array[0]}'}')"
499
+ elsif value[-1].blank?
500
+ str = "(#{'#{attr_key}'} >= '#{'#{date_array[0]}'}' or in_account_time_month >= '#{'#{date_array[0]}'}')"
501
+ end
502
+
503
+ elsif key.to_s.end_with?('_id')
504
+ str = ''
505
+ if value.size > 0
506
+ tmp = value.map {|item| item.to_i}.to_s
507
+ tmp.tr!('[', '(')
508
+ tmp.tr!(']', ')')
509
+ str = "#{'#{key}'} in #{'#{tmp}'}"
510
+ end
511
+
512
+ #多选模糊查询
513
+ elsif key.to_s.include?('multi_')
514
+ str = ""
515
+ attr_key = key.to_s.gsub('multi_', '')
516
+ value.each do |a|
517
+ next unless a.present?
518
+ tmp = "#{'#{attr_key}'} like '%#{'#{a}'}%'"
519
+ if a != value.first and str != ""
520
+ tmp = " or " + tmp
521
+ end
522
+ str += tmp
523
+ end
524
+ str = "(#{'#{str}'})"
525
+ else
526
+ if key == 'academic_category'
527
+ str = "#{'#{key}'} = '#{'#{value.upcase}'}'"
528
+ else
529
+ str = "#{'#{key.to_s}'}='#{'#{value}'}'"
530
+ end
531
+ end
532
+ if key != options.keys.first and search_string != "where "
533
+ str = " and " + str
534
+ end
535
+
536
+ search_string += str
537
+ end
538
+ if search_string == "where "
539
+ search_string = ""
540
+ end
541
+ # log(search_string)
542
+ return search_string
543
+ end
544
+ end
545
+
546
+ module AttributeType
547
+ DECIMAL = 'decimal'
548
+ STRING = 'string'
549
+ DATE = 'date'
550
+ end
551
+
552
+ def generate_pinyin_when_create
553
+ if self.deleted_at.blank?
554
+ self.class.attribute_names.each do |attribute|
555
+ self[attribute.intern] = PinYin.of_string(self[attribute.remove('_pinyin').intern]).join if attribute.include?('_pinyin')
556
+ end
557
+ end
558
+ end
559
+
560
+ end
561
+
562
+ File
563
+ # frozen_string_literal: true
564
+
565
+
566
+ APPLICATION_JSON_BUILDER = <<-File
567
+ json.partial! 'common/response_status', response: @response
568
+ page_params = {}
569
+ instance_variables.each do |iv|
570
+ begin
571
+ object = self.instance_variable_get(iv)
572
+ if object.respond_to?(:total_pages) && object.respond_to?(:total_count) && iv !=:@_config
573
+ page_params.merge!({total_pages: object.total_pages, total_count: object.total_count})
574
+ end
575
+ rescue => e
576
+ ylogi e
577
+ end
578
+ end
579
+
580
+ json.data do
581
+ json.merge! JSON.parse(yield)
582
+ if page_params.present?
583
+ json.merge! page_params
584
+ end
585
+ end
586
+ File
587
+
588
+ APPLICATION_HELPER = <<-File
589
+ # encoding: UTF-8
590
+ # frozen_string_literal: true
591
+
592
+ module ApplicationHelper
593
+ #
594
+ # 渲染json返回属性
595
+ #
596
+ # @param json [Unknown] json对象
597
+ # @param obj [ActiveRecord] 数据库表的对象
598
+ # @param attrs [Array] 需要渲染的表属性符号数组
599
+ #
600
+ def render_json_attrs(json, obj, attrs = nil)
601
+ # Rails.logger.info "obj=>#{'#{obj}'}"
602
+ if attrs.blank?
603
+ attrs = obj.class.columns.map(&:name)
604
+ end
605
+ attrs.each do |column|
606
+ next unless column != 'deleted_at'
607
+ key = column.to_sym
608
+ column_type = obj.class.columns.select { |c| c.name == column.to_s }.first.type
609
+ value = obj.__send__(column.to_sym)
610
+ if value.present?
611
+ value = value.to_time&.strftime('%F') if key.to_s == 'date' || key.to_s.include?('_date')
612
+ # 兼容代码
613
+ value = value.to_time&.strftime('%F %H:%M') if key.to_s =~ /_at$/ || key.to_s =~ /_time$/
614
+
615
+ # if (/^([a-zA-Z]+_)*id$/ =~ key).present? || key.to_s == 'whodunnit'
616
+ # if value.class == Array
617
+ # value = value.map { |v| v }
618
+ # else
619
+ # value = value
620
+ # end
621
+ # end
622
+ else
623
+ value = ''
624
+ value = false if value != true && column_type == :boolean
625
+ end
626
+ json.__send__(key, value)
627
+ end
628
+ end
629
+
630
+ def render_json_attrs_except(json, object, attrs = nil)
631
+ attrs = object.class.columns.map(&:name) - (attrs.map { |x| x.to_s }) if attrs.present?
632
+
633
+ render_json_attrs(json, object, attrs)
634
+ end
635
+
636
+ def render_json_array_partial(obj, array, particle, as)
637
+ obj.__send__('array!', array, partial: particle, as: as)
638
+ end
639
+
640
+ #
641
+ # 将准确时间转换成相对于当前的时间
642
+ #
643
+ def timeago(time)
644
+ return '' if time.blank?
645
+
646
+ if time.is_a?(String)
647
+ time = begin
648
+ Time.parse(time)
649
+ rescue
650
+ ''
651
+ end
652
+ elsif time.is_a?(Time)
653
+ time = time
654
+ end
655
+
656
+ return '' if time.blank?
657
+
658
+ time_now = Time.now
659
+
660
+ interval = (time_now - time).to_i
661
+
662
+ case interval
663
+ when 0 .. 3600
664
+ minutes = interval / 60
665
+
666
+ time = I18n.t('timeago.minutes', minutes: minutes)
667
+
668
+ when 3601 .. 86_400
669
+ hours = interval / 3600
670
+
671
+ time = I18n.t('timeago.hours', hours: hours)
672
+
673
+ when 86_401 .. 2_592_000
674
+ days = interval / 86_400
675
+
676
+ time = I18n.t('timeago.days', days: days)
677
+
678
+ else
679
+ time = time.strftime('%F %H:%M')
680
+ end
681
+
682
+ time
683
+ end
684
+
685
+ def get_model(model_name)
686
+ ActiveSupport::Dependencies.constantize(model_name.classify)
687
+ end
688
+
689
+
690
+ end
691
+ File
692
+
693
+ RESPONSE = <<-File
694
+ # frozen_string_literal: true
695
+ class Response
696
+ # 添加属性
697
+ attr_accessor :code, :message, :messages
698
+
699
+ #
700
+ # 状态码
701
+ #
702
+ module Code
703
+ # 添加模型常量国际化方法
704
+ # include Dictionary::Module::I18n
705
+
706
+ ################################################################################
707
+ #
708
+ # 20000 成功
709
+ #
710
+ ################################################################################
711
+
712
+ SUCCESS = '20000'
713
+
714
+ ################################################################################
715
+ #
716
+ # 3xxxx 数据相关
717
+ #
718
+ ################################################################################
719
+
720
+ # 用户绑定第三方账户
721
+
722
+ # 第三方账户已绑定其它用户
723
+ PROVIDER_BIND_ANOTHER_USER = '30010'
724
+
725
+ ################################################################################
726
+ #
727
+ # 4xxxx 业务相关
728
+ #
729
+ ################################################################################
730
+
731
+ # 非法请求
732
+ INVALID_REQUEST = '40300'
733
+
734
+ # 终端密钥错误
735
+ INVALID_TERMINAL_SESSION_KEY = '40301'
736
+
737
+ # 用户密钥错误
738
+ INVALID_USER_SESSION_KEY = '40302'
739
+
740
+ # 超出请求限制数
741
+ EXCEED_REQUEST_LIMIT = '40303'
742
+
743
+ # 版本号不适配
744
+ NOT_COMPATIBLE_REVISION = '40304'
745
+
746
+ # 访问令牌过期
747
+ ACCESS_TOKEN_EXPIRED = '40305'
748
+
749
+ ################################################################################
750
+ #
751
+ # 5xxxx 系统相关
752
+ #
753
+ ################################################################################
754
+
755
+ # 未知错误(通常在捕捉异常后使用)
756
+ ERROR = '50000'
757
+
758
+ # 请求参数缺失
759
+ # Todo: 移动到数据相关
760
+ MISS_REQUEST_PARAMS = '50001'
761
+
762
+ # 数据处理错误
763
+ # Todo: 移动到数据相关
764
+ DATA_PROCESS_ERROR = '51000'
765
+
766
+ # 数据缺失错误
767
+ # Todo: 移动到数据相关
768
+ DATA_MISS_ERROR = '51001'
769
+
770
+ ORDER_PAYMENT_COMPLETED = '55000'
771
+
772
+ NEED_LOGIN = '40100'
773
+
774
+ # 全部
775
+ # ALL = get_all_constants.map { |constant| constant.to_s.downcase }
776
+ end
777
+
778
+ #
779
+ # 实例对象
780
+ #
781
+ # @param code [Code] 编码
782
+ # @param message [String] 返回信息
783
+ # @param messages [Array] 可能的错误信息
784
+ #
785
+ # @return [Response] 返回实例化的对象
786
+ #
787
+ def initialize(code = Code::SUCCESS, message = '', messages = [])
788
+ @code = code
789
+ @message = message
790
+ @messages = messages
791
+ end
792
+
793
+ def method_missing(method_id, *arguments, &block)
794
+ method_message = *arguments.join
795
+ if (method_id.to_s =~ /^raise_[\w]+/) == 0
796
+ error_type = method_id.to_s.split('raise_')[1].upcase!
797
+ @code = "Response::Code::#{'#{error_type}'}".constantize
798
+ @message = method_message
799
+ raise StandardError.new(method_message)
800
+ else
801
+ super
802
+ end
803
+ end
804
+
805
+ def self.rescue(catch_block = nil)
806
+ response = self.new
807
+ Rails.logger.info "response为#{'#{response.to_json}'}"
808
+ begin
809
+ yield(response)
810
+ rescue => e
811
+ if (e.class != StandardError && ENV['RAILS_ENV'] == 'development')
812
+ throw e
813
+ end
814
+ catch_block.call if catch_block.present?
815
+ if response.code == Code::SUCCESS
816
+ response.code = Code::ERROR
817
+ response.message = e.message
818
+ end
819
+ end
820
+
821
+ response
822
+ end
823
+
824
+ #
825
+ # 生成一个错误异常
826
+ #
827
+ # @example
828
+ # Response.error
829
+ # => #<Response:0x007feb7b049638 @code="50000", @message="未知异常", @messages=[]>
830
+ #
831
+ # @return [Response] 响应对象
832
+ #
833
+ def self.error message = nil
834
+ response = self.new
835
+ response.code = Code::ERROR
836
+ response.message = message || '未知异常'
837
+
838
+ response
839
+ end
840
+
841
+ # private
842
+
843
+ #
844
+ # 抛出异常
845
+ #
846
+ # @example
847
+ # Response.new.raise(Response::Code::ERROR, 'some error message')
848
+ #
849
+ # @param code [Code] 编码
850
+ # @param message [String] 信息
851
+ #
852
+ # def _raise(code, message)
853
+ # @code = code
854
+ # @message = message
855
+ #
856
+ # raise StandardError, message
857
+ # end
858
+ end
859
+
860
+ File
861
+
862
+ RESPONSE_JSON = <<-File
863
+ # frozen_string_literal: true
864
+ json.status do |res|
865
+ if response.present?
866
+ res.code response.code || Response::Code::ERROR
867
+ res.message response.message
868
+ else
869
+ res.code Response::Code::ERROR
870
+ res.message ''
871
+ end
872
+
873
+ res.no SecureRandom.uuid
874
+ end
875
+
876
+ File
877
+
878
+ end
879
+
880
+ end
881
+
882
+ end