sofav 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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