sofav 0.2.0

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +35 -0
  4. data/Rakefile +34 -0
  5. data/app/builders/admin/form_builder.rb +250 -0
  6. data/app/controllers/application_controller.rb +23 -0
  7. data/app/decorators/base_decorator.rb +172 -0
  8. data/app/helpers/admin/core_helper.rb +237 -0
  9. data/app/helpers/admin/show_view_helper.rb +69 -0
  10. data/app/helpers/admin/tags_helper.rb +104 -0
  11. data/app/services/active_record/search_service.rb +121 -0
  12. data/app/views/admin/application/_breadcrumb_nav.html.erb +10 -0
  13. data/app/views/admin/application/_collection.html.erb +79 -0
  14. data/app/views/admin/application/_save_js.js.erb +20 -0
  15. data/app/views/admin/application/_sidebar.html.erb +62 -0
  16. data/app/views/admin/application/_topbar.html.erb +32 -0
  17. data/app/views/admin/application/actions/charge.html.erb +3 -0
  18. data/app/views/admin/application/actions/destroy.html.erb +5 -0
  19. data/app/views/admin/application/actions/edit.html.erb +1 -0
  20. data/app/views/admin/application/actions/edit_sights.html.erb +1 -0
  21. data/app/views/admin/application/actions/feedback.html.erb +4 -0
  22. data/app/views/admin/application/actions/index_charge.html.erb +1 -0
  23. data/app/views/admin/application/actions/index_destroy.html.erb +1 -0
  24. data/app/views/admin/application/actions/index_edit.html.erb +1 -0
  25. data/app/views/admin/application/actions/index_edit_sights.html.erb +1 -0
  26. data/app/views/admin/application/actions/index_show.html.erb +1 -0
  27. data/app/views/admin/application/actions/new.html.erb +1 -0
  28. data/app/views/admin/application/create.js.erb +1 -0
  29. data/app/views/admin/application/destroy.js.erb +6 -0
  30. data/app/views/admin/application/edit.html.erb +18 -0
  31. data/app/views/admin/application/index.html.erb +23 -0
  32. data/app/views/admin/application/new.html.erb +18 -0
  33. data/app/views/admin/application/partials/_map_pos_picker.html.erb +101 -0
  34. data/app/views/admin/application/partials/_sort_script.html.erb +32 -0
  35. data/app/views/admin/application/show.html.erb +16 -0
  36. data/app/views/admin/application/update.js.erb +1 -0
  37. data/app/views/admin/dashboard/index.html.erb +8 -0
  38. data/app/views/layouts/admin.html.erb +30 -0
  39. data/config/locales/devise.en.yml +64 -0
  40. data/config/locales/devise.zh-CN.yml +120 -0
  41. data/config/locales/doorkeeper.en.yml +124 -0
  42. data/config/locales/doorkeeper.zh-CN.yml +132 -0
  43. data/config/locales/en.yml +23 -0
  44. data/config/locales/enumerize/defaults.zh-CN.yml +7 -0
  45. data/config/locales/kaminari.zh-CN.yml +17 -0
  46. data/config/locales/rails.zh-CN.yml +204 -0
  47. data/config/locales/views/actions.zh-CN.yml +21 -0
  48. data/config/locales/views/attributes.zh-CN.yml +15 -0
  49. data/config/locales/views/breadcrumb.zh-CN.yml +5 -0
  50. data/config/locales/views/common.zh-CN.yml +7 -0
  51. data/config/locales/views/enums.zh-CN.yml +13 -0
  52. data/config/locales/views/profiles.zh-CN.yml +3 -0
  53. data/lib/generators/sofav/USAGE +0 -0
  54. data/lib/generators/sofav/sofav_generator.rb +50 -0
  55. data/lib/generators/sofav/templates/activerecord.zh-CN.yml +4 -0
  56. data/lib/generators/sofav/templates/attribute_types.zh-CN.yml +2 -0
  57. data/lib/sofav.rb +6 -0
  58. data/lib/sofav/decorator.rb +47 -0
  59. data/lib/sofav/local.rb +52 -0
  60. data/lib/sofav/version.rb +3 -0
  61. data/lib/tasks/sofa_tasks.rake +4 -0
  62. data/vendor/assets/javascripts/admin/here.js +0 -0
  63. data/vendor/assets/javascripts/bootbox.js +1020 -0
  64. data/vendor/assets/javascripts/bootstrap.js +2377 -0
  65. data/vendor/assets/javascripts/jquery-ui.js +5169 -0
  66. data/vendor/assets/javascripts/select2.js +5725 -0
  67. data/vendor/assets/stylesheets/bootstrap.css +6800 -0
  68. data/vendor/assets/stylesheets/bootstrap.css.map +1 -0
  69. data/vendor/assets/stylesheets/jquery-ui.css +453 -0
  70. data/vendor/assets/stylesheets/select2.css +484 -0
  71. metadata +211 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e60d0d8ba1013b0ea2c8d3cfa78c2d6243568a89
4
+ data.tar.gz: f7fd74fee86b39adbbda912402fdba14bacc4f6a
5
+ SHA512:
6
+ metadata.gz: 2bebb18fb8e41a8ed3dc0a41e8a37b0c18791f0339366d3652678ab8ff303b45ae2cc27072c257bd90295d2c9e5d4895858032591ccf09cd49daa03e99fff12f
7
+ data.tar.gz: 8ce5c387a0096a5b9a97d4c333644d6e30ab542a6de1ac77c051c4cce34cd4b6d7be963e61a4982a6db2902e067808330df48bd3a4929a30576e4b7ba8b6e7b2
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 yangdiei
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Sofa
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ rails generate sofav NAME [field:type field:type] [options]
6
+ ```
7
+ rails g sofav User name:string age:integer
8
+ ```
9
+
10
+ ## Installation
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'sofav'
15
+ ```
16
+
17
+ And then execute:
18
+ ```bash
19
+ $ bundle
20
+ ```
21
+
22
+ Or install it yourself as:
23
+ ```bash
24
+ $ gem install sofa
25
+ ```
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+
34
+ ## License
35
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Sofav'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,250 @@
1
+ module Admin
2
+ class FormBuilder < ActionView::Helpers::FormBuilder
3
+ delegate :model, :decorator, :decorate, :record, :records, :concat, to: :@template
4
+
5
+ def label_tag(method, options = {})
6
+ label_class = Array(options[:label_class]) || []
7
+ label_class << ['control-label', options[:block] ? 'col-sm-2' : 'col-sm-4'] if label_class.blank?
8
+ label_class << 'required' if options[:required]
9
+ @template.content_tag(:label, model.human_attribute_name(method), class: label_class.flatten)
10
+ end
11
+
12
+ def input_dom_id(field_name)
13
+ '_form_id_'.concat(field_name.to_s)
14
+ end
15
+
16
+ def field_wrapper(method, options = {}, &block)
17
+ label_options = options.extract!(:label_class, :required, :block)
18
+ is_block = label_options[:block]
19
+ show_label = options.delete(:show_label)
20
+ options[:class] ||= 'form-control'
21
+ options.merge!(id: input_dom_id(method))
22
+
23
+ @template.content_tag(:li, class: is_block ? 'col-sm-12' : 'col-sm-6') do
24
+ @template.content_tag(:div, class: 'form-group') do
25
+ content = (show_label.nil? || show_label) ? [label_tag(method, label_options)] : [@template.content_tag(:div, class: 'col-sm-2'){}]
26
+ content << @template.content_tag(:div, yield(block), class: is_block ? 'col-sm-10' : 'col-sm-8')
27
+ content.join.html_safe
28
+ end
29
+ end
30
+ end
31
+
32
+ def admin_nested_fields(method, options = {})
33
+ field_wrapper(method, options) do
34
+ fields_content = []
35
+ fields_content << @template.content_tag(:div, id: "#{method}_nested_form") do
36
+ nested_content = []
37
+ nested_content << self.fields_for(method.to_sym) do |ff|
38
+ @template.render("#{method.to_s.singularize}_fields", f: ff)
39
+ end
40
+
41
+ nested_content << @template.content_tag(:div, class: 'col-sm-12') do
42
+ btns_content = [@template.link_to_add_association('添加', self, method.to_sym, class: 'btn btn-sm btn-success'), "&nbsp;"]
43
+ btns_content << @template.button_tag(:input, class: "sort-btn btn btn-sm btn-success", type: "button", id: "#{method}-sort-btn") { "排序" }
44
+ btns_content.join.html_safe
45
+ end
46
+
47
+ nested_content.join.html_safe
48
+ end
49
+
50
+ fields_content << @template.render("admin/application/partials/sort_script",
51
+ sort_btn_id: "##{method}-sort-btn",
52
+ container_id: "##{method}_nested_form",
53
+ resource_parts: method.pluralize)
54
+
55
+ fields_content << @template.content_tag(:script) do
56
+ %(
57
+ $(document).on('turbolinks:load', function () {
58
+ Cocoon();
59
+ });
60
+ ).html_safe
61
+ end
62
+ fields_content.join.html_safe
63
+ end
64
+ end
65
+
66
+ def admin_render_field(method, options = {})
67
+ field_wrapper(method, options) do
68
+ @template.render("#{method.to_s.singularize}", f: self)
69
+ end
70
+ end
71
+
72
+ def admin_display_field(method, options = {})
73
+ field_wrapper(method, options) do
74
+ @template.content_tag(:span, record.try(method))
75
+ end
76
+ end
77
+
78
+ def admin_text_field(method, options = {})
79
+ field_wrapper(method, options) do
80
+ @template.text_field(@object_name, method, objectify_options(options))
81
+ end
82
+ end
83
+
84
+ def admin_password_field(method, options = {})
85
+ field_wrapper(method, options) do
86
+ @template.password_field(@object_name, method, objectify_options(options))
87
+ end
88
+ end
89
+
90
+ def admin_number_field(method, options = {})
91
+ field_wrapper(method, options) do
92
+ @template.number_field(@object_name, method, objectify_options(options))
93
+ end
94
+ end
95
+
96
+ def admin_generic_field(type, method, options = {})
97
+ field_wrapper(method, options) do
98
+ send type, @object_name, method, objectify_options(options)
99
+ end
100
+ end
101
+
102
+ def admin_file_field(method, options = {})
103
+ file_url = record.try(method)
104
+ file_url = file_url.class.superclass == CarrierWave::Uploader::Base ? file_url.try('url') : file_url
105
+
106
+ field_wrapper(method, options) do
107
+ content = [@template.file_field(@object_name, method, objectify_options(options))]
108
+ content << @template.link_to(file_url, target: '_blank') {"点击查看"}
109
+ content.join.html_safe
110
+ end
111
+ end
112
+
113
+ def admin_image_field(method, options = {})
114
+ field_wrapper(method, options) do
115
+ img_url = record.try(method)
116
+ img_url = img_url.class.superclass == CarrierWave::Uploader::Base ? img_url.try('url') : img_url
117
+ content = [@template.link_to(img_url, target: '_blank') do
118
+ decorate.respond_to?("human_#{method}") ? decorate.human(method) : @template.image_tag(img_url)
119
+ end]
120
+ content << @template.file_field(@object_name, method, objectify_options(options))
121
+ content.join.html_safe
122
+ end
123
+ end
124
+
125
+ def admin_collection_check_boxes(method, options = {})
126
+ collection, value_method = options.delete(:collection), options.delete(:value_method)
127
+ text_method, html_options = options.delete(:text_method), options.delete(:html_options) || {}
128
+ field_wrapper(method, options) do
129
+ @template.collection_check_boxes(@object_name, method, eval(collection), value_method, text_method, objectify_options(options), @default_options.merge(html_options)) do |b|
130
+ @template.content_tag(:span) { [b.check_box, b.text].join(' ').html_safe }
131
+ end
132
+ end
133
+ end
134
+
135
+ def admin_collection_select2(method, options = {})
136
+ collection, value_method = options.delete(:collection), options.delete(:value_method)
137
+ text_method, html_options = options.delete(:text_method), options.delete(:html_options) || {}
138
+ is_array = options.delete(:is_array)
139
+ select2_options = options.delete(:select2_options)
140
+ options.merge!(prompt: true)
141
+ html_options.merge!(options.extract!(:label_class, :required, :block))
142
+ html_options.merge!(name: "#{@object_name}[#{method}][]") if is_array
143
+ sel_scripts = field_wrapper(method, html_options) do
144
+ @template.collection_select(@object_name, method, eval(collection), value_method, text_method, objectify_options(options), @default_options.merge(html_options))
145
+ end
146
+ select2_scripts = @template.content_tag(:script) { "$('##{input_dom_id(method)}').select2(#{select2_options.to_json});".html_safe }
147
+ sel_scripts.concat(select2_scripts)
148
+ end
149
+
150
+ def admin_collection_select(method, options = {})
151
+ collection, value_method = options.delete(:collection), options.delete(:value_method)
152
+ text_method, html_options = options.delete(:text_method), options.delete(:html_options) || {}
153
+ is_array = options.delete(:is_array)
154
+ options.merge!(prompt: true)
155
+ html_options.merge!(options.extract!(:label_class, :required, :block))
156
+ html_options.merge!(name: "#{@object_name}[#{method}][]") if is_array
157
+ field_wrapper(method, html_options) do
158
+ @template.collection_select(@object_name, method, eval(collection), value_method, text_method, objectify_options(options), @default_options.merge(html_options))
159
+ end
160
+ end
161
+
162
+ def admin_text_area(method, options = {})
163
+ field_wrapper(method, options) do
164
+ @template.text_area(@object_name, method, objectify_options(options))
165
+ end
166
+ end
167
+
168
+ def admin_date_select(method, options = {})
169
+ field_wrapper(method, options) do
170
+ options[:class] = [options[:class], 'datepicker'].flatten
171
+ @template.text_field(@object_name, method, objectify_options(options))
172
+ end
173
+ end
174
+
175
+ def admin_datetime_select(method, options = {})
176
+ field_wrapper(method, options) do
177
+ options[:class] = [options[:class], 'datetimepicker'].flatten
178
+ @template.text_field(@object_name, method, objectify_options(options))
179
+ end
180
+ end
181
+
182
+ def admin_collection_radio_buttons(method, options = {})
183
+ collection, value_method = options.delete(:collection), options.delete(:value_method)
184
+ text_method, html_options = options.delete(:text_method), options.delete(:html_options) || {}
185
+ field_wrapper(method, options) do
186
+ @template.collection_radio_buttons(@object_name, method, eval(collection), value_method, text_method, objectify_options(options), @default_options.merge(html_options)) do |b|
187
+ @template.content_tag(:span, style: 'height: 34px;display: inline-block;') { [b.radio_button, b.text].join(' ').html_safe }
188
+ end
189
+ end
190
+ end
191
+
192
+ def build_form_for(decorator, *attribute_name_list)
193
+ fields_hash = []
194
+ attribute_name_list.each do |attribute_name|
195
+ fields_hash = decorator.try(attribute_name)
196
+ break if !fields_hash.empty?
197
+ end
198
+ if fields_hash.empty?
199
+ fields_hash = decorator.try(:new_attributes)
200
+ end
201
+ profiles = fields_hash.fetch(:profiles, [])
202
+
203
+ form_fields = if profiles.present?
204
+ profiles.collect { |profile|
205
+ fields = fields_hash.fetch(profile.to_sym, {})
206
+ content = []
207
+ content << @template.content_tag(:h3, I18n.t("profiles.#{profile}", default: profile), class: 'lead clearfix')
208
+ content << build_fields_for(decorator, fields)
209
+ content.join.html_safe
210
+ }.join.html_safe
211
+ else
212
+ build_fields_for(decorator, fields_hash)
213
+ end
214
+ [form_fields, build_form_buttons].join.html_safe
215
+ end
216
+
217
+ def build_fields_for(decorator, fields)
218
+ @template.content_tag(:ul, class: 'row list-unstyled') do
219
+ fields.each do |field_name|
220
+ options = decorator.try(:attribute_type_for, field_name, true) || {type: 'text_field', required: false}
221
+ type = options.delete(:type)
222
+
223
+ if self.respond_to?('admin_'.concat(type))
224
+ concat(send('admin_'.concat(type), field_name, options))
225
+ else
226
+ concat admin_generic_field(type, field_name, options)
227
+ end
228
+ end
229
+ end
230
+ end
231
+
232
+ def build_form_buttons
233
+ lead = @template.content_tag(:h3, nil, class: 'lead clearfix')
234
+ tags = @template.content_tag(:div, [submit_tag, ' ', reset_tag].join.html_safe, class: 'col-sm-12')
235
+ lead.concat(@template.content_tag(:div, tags, class: 'row'))
236
+ end
237
+
238
+ def submit_tag
239
+ tag_text = @template.content_tag(:i, nil, class: 'glyphicon glyphicon-check')
240
+ tag_text.concat(@template.content_tag(:span, '提交'))
241
+ @template.content_tag(:button, tag_text, class: 'btn btn-icon btn-info', type: 'submit')
242
+ end
243
+
244
+ def reset_tag
245
+ tag_text = @template.content_tag(:i, nil, class: 'glyphicon glyphicon-repeat')
246
+ tag_text.concat(@template.content_tag(:span, '重置'))
247
+ @template.content_tag(:button, tag_text, class: 'btn btn-icon btn-warning', type: 'reset')
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,23 @@
1
+ module Admin
2
+ class ApplicationController < ::ApplicationController
3
+ layout "admin"
4
+
5
+ include Admin::ActionController
6
+ include Admin::CommonActions
7
+ include ApplicationHelper
8
+
9
+ helper_method :scope, :model, :decorator, :record, :decorate, :records, :render_to_string
10
+
11
+ before_action :authenticate_user!
12
+ before_action do
13
+ if current_user.user? or current_user.role.blank?
14
+ render :file => "public/403.html", :status => :unauthorized, :layout => false
15
+ end
16
+ end
17
+
18
+ before_action do
19
+ prepend_view_path 'app/views/admin/application'
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,172 @@
1
+ class BaseDecorator < Draper::Decorator
2
+ extend Dry::Configurable
3
+
4
+ # 对应的model class
5
+ setting :model
6
+
7
+ DEFINITIONS = {
8
+ # 属性定义列表
9
+ attribute_types: {},
10
+
11
+ # index page用到的字段/筛选/搜索
12
+ collection_filters: [],
13
+ collection_search: {},
14
+ collection_attributes: [],
15
+
16
+ # new/edit page用到的字段列表
17
+ form_attributes: [],
18
+ edit_form_attributes: [],
19
+
20
+ # show page 用到的字段列表
21
+ show_page_attributes: [],
22
+
23
+ # class/instance 操作列表
24
+ permitted_class_methods: {},
25
+ permitted_instance_methods: {},
26
+
27
+ extra_permitted_attributes: {}
28
+ }.freeze
29
+
30
+ DEFINITIONS.each do |key, default_value|
31
+ setting key, default_value
32
+ delegate key, to: :class
33
+ end
34
+
35
+ def human(field)
36
+ value = try("human_#{field}") || try(field) || object.try("#{field}_text") || object.try(field)
37
+ value = field.split('.').inject(object) {
38
+ |result, method| result.try(method)
39
+ } if field.include?('.')
40
+
41
+ case value
42
+ when ActiveSupport::TimeWithZone
43
+ value.strftime('%Y-%m-%d %H:%M:%S')
44
+ when TrueClass
45
+ I18n.t("#{field}.true_html", default: '-').html_safe
46
+ when FalseClass
47
+ I18n.t("#{field}.false_html", default: '-').html_safe
48
+ else
49
+ value.presence || '-'
50
+ end
51
+ end
52
+
53
+ class << self
54
+ delegate :model, to: :config
55
+
56
+ def inherited(subclass)
57
+ super
58
+
59
+ subclass.configure do |config|
60
+ config.model = subclass.name.remove(/Decorator\Z/).singularize.safe_constantize
61
+
62
+ scope = config.model.model_name.singular
63
+ config.attribute_types = I18n.t(['attribute_types', scope].join('.'), default: {}).deep_dup
64
+ I18n.t(['decorator', scope].join('.'), default: {}).map { |key, value| config.send("#{key}=", value) }
65
+
66
+ config.model.columns_hash.each do |name, col|
67
+ name = name.to_sym
68
+ if config.attribute_types[name].nil?
69
+ if col.array
70
+ config.attribute_types[name] = {
71
+ type: 'collection_select',
72
+ collection: '[]',
73
+ text_method: :last,
74
+ value_method: :first,
75
+ }
76
+ else
77
+ case col.type
78
+ when 'integer', 'float'
79
+ config.attribute_types[name] = {
80
+ type: 'number_field',
81
+ required: false
82
+ }
83
+ when 'datetime'
84
+ config.attribute_types[name] = {
85
+ type: 'datetime_select',
86
+ required: false
87
+ }
88
+ when 'boolean'
89
+ config.attribute_types[name] = {
90
+ type: 'collection_check_boxes',
91
+ required: false
92
+ }
93
+ when 'date'
94
+ config.attribute_types[name] = {
95
+ type: 'date_select',
96
+ required: false
97
+ }
98
+ else
99
+ config.attribute_types[name] = {
100
+ type: 'text_field',
101
+ required: false
102
+ }
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+
109
+ end
110
+ end
111
+
112
+ # 设置对应的class
113
+ def decorate_to(klass)
114
+ config.model = klass
115
+ end
116
+
117
+ DEFINITIONS.keys.each do |method_name|
118
+ define_method(method_name) { |&block|
119
+ if block
120
+ config.send("#{method_name}=", block.call)
121
+ else
122
+ config.send(method_name)
123
+ end
124
+ }
125
+ end
126
+
127
+ # 获取某个属性的定义
128
+ def attribute_type_for(attribute_name, quiet = false)
129
+ config.attribute_types.fetch(attribute_name.to_sym) do
130
+ fail attribute_not_found_message(attribute_name) unless quiet
131
+ end.deep_dup
132
+ end
133
+
134
+ # 表单必填字段列表
135
+ def required_attributes
136
+ config.attribute_types.collect { |name, field| name if field[:required] }.compact
137
+ end
138
+
139
+ # 表单允许提交的参数
140
+ def permitted_attributes
141
+ _attributes = config.form_attributes
142
+
143
+ if _attributes.is_a?(Hash)
144
+ profiles = _attributes.fetch(:profiles, [])
145
+ _attributes = profiles.collect { |profile| _attributes.fetch(profile.to_sym, []) }.flatten.uniq
146
+ # _attributes = _attributes.each {|attr| _attributes << "#{attr}_attributes"}
147
+ end
148
+
149
+ array, hash = [], {}
150
+ _attributes.each do |field_name|
151
+ attribute_type_for(field_name)[:is_array] ? hash.merge!(field_name => []) : array.push(field_name)
152
+ end
153
+
154
+ [array, hash].append(config.extra_permitted_attributes)
155
+ #.append(filters: config.collection_filters.keys)
156
+ end
157
+
158
+ def permitted_class_methods_for(action_name)
159
+ config.permitted_class_methods.fetch(action_name.to_sym, [])
160
+ end
161
+
162
+ def permitted_instance_methods_for(action_name)
163
+ config.permitted_instance_methods.fetch(action_name.to_sym, [])
164
+ end
165
+
166
+ private
167
+
168
+ def attribute_not_found_message(attribute_name)
169
+ "Attribute #{attribute_name} could not be found in #{self}.attribute_types"
170
+ end
171
+ end
172
+ end