easy_mongoid_tag 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +89 -0
  4. data/Guardfile +22 -0
  5. data/LICENSE +191 -0
  6. data/README.textile +34 -0
  7. data/easy_mongoid_tag.gemspec +29 -0
  8. data/lib/easy_mongoid_tag.rb +5 -0
  9. data/lib/easy_mongoid_tag/tag.rb +151 -0
  10. data/lib/easy_mongoid_tag/version.rb +4 -0
  11. data/lib/mongoid_extensions/extension_field.rb +14 -0
  12. data/prototype/book.rb +119 -0
  13. data/prototype/mongodb.yml +6 -0
  14. data/spec/function_spec.rb +43 -0
  15. data/spec/mongodb.yml +6 -0
  16. data/spec/spec_helper.rb +54 -0
  17. data/spec/tag_spec.rb +98 -0
  18. data/test/read_book/.gitignore +15 -0
  19. data/test/read_book/Gemfile +39 -0
  20. data/test/read_book/Gemfile.lock +119 -0
  21. data/test/read_book/README.rdoc +261 -0
  22. data/test/read_book/Rakefile +7 -0
  23. data/test/read_book/app/assets/images/rails.png +0 -0
  24. data/test/read_book/app/assets/javascripts/application.js +15 -0
  25. data/test/read_book/app/assets/stylesheets/application.css +13 -0
  26. data/test/read_book/app/controllers/application_controller.rb +3 -0
  27. data/test/read_book/app/helpers/application_helper.rb +2 -0
  28. data/test/read_book/app/mailers/.gitkeep +0 -0
  29. data/test/read_book/app/models/.gitkeep +0 -0
  30. data/test/read_book/app/models/book.rb +11 -0
  31. data/test/read_book/app/views/layouts/application.html.erb +14 -0
  32. data/test/read_book/config.ru +4 -0
  33. data/test/read_book/config/application.rb +68 -0
  34. data/test/read_book/config/boot.rb +6 -0
  35. data/test/read_book/config/environment.rb +5 -0
  36. data/test/read_book/config/environments/development.rb +31 -0
  37. data/test/read_book/config/environments/production.rb +64 -0
  38. data/test/read_book/config/environments/test.rb +35 -0
  39. data/test/read_book/config/initializers/backtrace_silencers.rb +7 -0
  40. data/test/read_book/config/initializers/inflections.rb +15 -0
  41. data/test/read_book/config/initializers/mime_types.rb +5 -0
  42. data/test/read_book/config/initializers/secret_token.rb +7 -0
  43. data/test/read_book/config/initializers/session_store.rb +8 -0
  44. data/test/read_book/config/initializers/wrap_parameters.rb +10 -0
  45. data/test/read_book/config/locales/en.yml +5 -0
  46. data/test/read_book/config/mongoid.yml +80 -0
  47. data/test/read_book/config/routes.rb +58 -0
  48. data/test/read_book/db/seeds.rb +7 -0
  49. data/test/read_book/lib/assets/.gitkeep +0 -0
  50. data/test/read_book/lib/tasks/.gitkeep +0 -0
  51. data/test/read_book/log/.gitkeep +0 -0
  52. data/test/read_book/public/404.html +26 -0
  53. data/test/read_book/public/422.html +26 -0
  54. data/test/read_book/public/500.html +25 -0
  55. data/test/read_book/public/favicon.ico +0 -0
  56. data/test/read_book/public/index.html +241 -0
  57. data/test/read_book/public/robots.txt +5 -0
  58. data/test/read_book/script/rails +6 -0
  59. data/test/read_book/test/fixtures/.gitkeep +0 -0
  60. data/test/read_book/test/fixtures/books.yml +11 -0
  61. data/test/read_book/test/functional/.gitkeep +0 -0
  62. data/test/read_book/test/integration/.gitkeep +0 -0
  63. data/test/read_book/test/performance/browsing_test.rb +12 -0
  64. data/test/read_book/test/test_helper.rb +7 -0
  65. data/test/read_book/test/unit/.gitkeep +0 -0
  66. data/test/read_book/test/unit/book_test.rb +7 -0
  67. data/test/read_book/vendor/assets/javascripts/.gitkeep +0 -0
  68. data/test/read_book/vendor/assets/stylesheets/.gitkeep +0 -0
  69. data/test/read_book/vendor/plugins/.gitkeep +0 -0
  70. metadata +282 -0
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ # A sample Gemfile
2
+ source "http://ruby.taobao.org/"
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,89 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ easy_mongoid_tag (0.0.1)
5
+ mongoid (~> 3.1.0)
6
+
7
+ GEM
8
+ remote: http://ruby.taobao.org/
9
+ specs:
10
+ activemodel (3.2.14)
11
+ activesupport (= 3.2.14)
12
+ builder (~> 3.0.0)
13
+ activesupport (3.2.14)
14
+ i18n (~> 0.6, >= 0.6.4)
15
+ multi_json (~> 1.0)
16
+ builder (3.0.4)
17
+ childprocess (0.3.9)
18
+ ffi (~> 1.0, >= 1.0.11)
19
+ coderay (1.0.9)
20
+ diff-lcs (1.2.4)
21
+ ffi (1.9.0)
22
+ formatador (0.2.4)
23
+ guard (1.8.2)
24
+ formatador (>= 0.2.4)
25
+ listen (>= 1.0.0)
26
+ lumberjack (>= 1.0.2)
27
+ pry (>= 0.9.10)
28
+ thor (>= 0.14.6)
29
+ guard-rspec (3.0.2)
30
+ guard (>= 1.8)
31
+ rspec (~> 2.13)
32
+ guard-spork (1.5.1)
33
+ childprocess (>= 0.2.3)
34
+ guard (>= 1.1)
35
+ spork (>= 0.8.4)
36
+ i18n (0.6.5)
37
+ listen (1.3.0)
38
+ rb-fsevent (>= 0.9.3)
39
+ rb-inotify (>= 0.9)
40
+ rb-kqueue (>= 0.2)
41
+ lumberjack (1.0.4)
42
+ method_source (0.8.2)
43
+ mongoid (3.1.4)
44
+ activemodel (~> 3.2)
45
+ moped (~> 1.4)
46
+ origin (~> 1.0)
47
+ tzinfo (~> 0.3.22)
48
+ mongoid-rspec (1.9.0)
49
+ mongoid (>= 3.0.1)
50
+ rake
51
+ rspec (>= 2.14)
52
+ moped (1.5.1)
53
+ multi_json (1.7.9)
54
+ origin (1.1.0)
55
+ pry (0.9.12.2)
56
+ coderay (~> 1.0.5)
57
+ method_source (~> 0.8)
58
+ slop (~> 3.4)
59
+ rake (10.1.0)
60
+ rb-fsevent (0.9.3)
61
+ rb-inotify (0.9.1)
62
+ ffi (>= 0.5.0)
63
+ rb-kqueue (0.2.0)
64
+ ffi (>= 0.5.0)
65
+ rspec (2.14.1)
66
+ rspec-core (~> 2.14.0)
67
+ rspec-expectations (~> 2.14.0)
68
+ rspec-mocks (~> 2.14.0)
69
+ rspec-core (2.14.5)
70
+ rspec-expectations (2.14.2)
71
+ diff-lcs (>= 1.1.3, < 2.0)
72
+ rspec-mocks (2.14.3)
73
+ slop (3.4.6)
74
+ spork (0.9.2)
75
+ terminal-notifier-guard (1.5.3)
76
+ thor (0.18.1)
77
+ tzinfo (0.3.37)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ easy_mongoid_tag!
84
+ guard (~> 1.8.0)
85
+ guard-rspec (~> 3.0.0)
86
+ guard-spork (~> 1.5.1)
87
+ mongoid-rspec (~> 1.9.0)
88
+ rspec (~> 2.14.1)
89
+ terminal-notifier-guard (~> 1.5.3)
data/Guardfile ADDED
@@ -0,0 +1,22 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, :cli => "--color -f nested" do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
10
+
11
+ guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
12
+ watch('config/application.rb')
13
+ watch('config/environment.rb')
14
+ watch('config/environments/test.rb')
15
+ watch(%r{^config/initializers/.+\.rb$})
16
+ watch('Gemfile.lock')
17
+ watch('spec/spec_helper.rb') { :rspec }
18
+ watch('test/test_helper.rb') { :test_unit }
19
+ watch(%r{features/support/}) { :cucumber }
20
+ end
21
+
22
+ notification :terminal_notifier
data/LICENSE ADDED
@@ -0,0 +1,191 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction, and
10
+ distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright
13
+ owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all other entities
16
+ that control, are controlled by, or are under common control with that entity.
17
+ For the purposes of this definition, "control" means (i) the power, direct or
18
+ indirect, to cause the direction or management of such entity, whether by
19
+ contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20
+ outstanding shares, or (iii) beneficial ownership of such entity.
21
+
22
+ "You" (or "Your") shall mean an individual or Legal Entity exercising
23
+ permissions granted by this License.
24
+
25
+ "Source" form shall mean the preferred form for making modifications, including
26
+ but not limited to software source code, documentation source, and configuration
27
+ files.
28
+
29
+ "Object" form shall mean any form resulting from mechanical transformation or
30
+ translation of a Source form, including but not limited to compiled object code,
31
+ generated documentation, and conversions to other media types.
32
+
33
+ "Work" shall mean the work of authorship, whether in Source or Object form, made
34
+ available under the License, as indicated by a copyright notice that is included
35
+ in or attached to the work (an example is provided in the Appendix below).
36
+
37
+ "Derivative Works" shall mean any work, whether in Source or Object form, that
38
+ is based on (or derived from) the Work and for which the editorial revisions,
39
+ annotations, elaborations, or other modifications represent, as a whole, an
40
+ original work of authorship. For the purposes of this License, Derivative Works
41
+ shall not include works that remain separable from, or merely link (or bind by
42
+ name) to the interfaces of, the Work and Derivative Works thereof.
43
+
44
+ "Contribution" shall mean any work of authorship, including the original version
45
+ of the Work and any modifications or additions to that Work or Derivative Works
46
+ thereof, that is intentionally submitted to Licensor for inclusion in the Work
47
+ by the copyright owner or by an individual or Legal Entity authorized to submit
48
+ on behalf of the copyright owner. For the purposes of this definition,
49
+ "submitted" means any form of electronic, verbal, or written communication sent
50
+ to the Licensor or its representatives, including but not limited to
51
+ communication on electronic mailing lists, source code control systems, and
52
+ issue tracking systems that are managed by, or on behalf of, the Licensor for
53
+ the purpose of discussing and improving the Work, but excluding communication
54
+ that is conspicuously marked or otherwise designated in writing by the copyright
55
+ owner as "Not a Contribution."
56
+
57
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58
+ of whom a Contribution has been received by Licensor and subsequently
59
+ incorporated within the Work.
60
+
61
+ 2. Grant of Copyright License.
62
+
63
+ Subject to the terms and conditions of this License, each Contributor hereby
64
+ grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65
+ irrevocable copyright license to reproduce, prepare Derivative Works of,
66
+ publicly display, publicly perform, sublicense, and distribute the Work and such
67
+ Derivative Works in Source or Object form.
68
+
69
+ 3. Grant of Patent License.
70
+
71
+ Subject to the terms and conditions of this License, each Contributor hereby
72
+ grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73
+ irrevocable (except as stated in this section) patent license to make, have
74
+ made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75
+ such license applies only to those patent claims licensable by such Contributor
76
+ that are necessarily infringed by their Contribution(s) alone or by combination
77
+ of their Contribution(s) with the Work to which such Contribution(s) was
78
+ submitted. If You institute patent litigation against any entity (including a
79
+ cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80
+ Contribution incorporated within the Work constitutes direct or contributory
81
+ patent infringement, then any patent licenses granted to You under this License
82
+ for that Work shall terminate as of the date such litigation is filed.
83
+
84
+ 4. Redistribution.
85
+
86
+ You may reproduce and distribute copies of the Work or Derivative Works thereof
87
+ in any medium, with or without modifications, and in Source or Object form,
88
+ provided that You meet the following conditions:
89
+
90
+ You must give any other recipients of the Work or Derivative Works a copy of
91
+ this License; and
92
+ You must cause any modified files to carry prominent notices stating that You
93
+ changed the files; and
94
+ You must retain, in the Source form of any Derivative Works that You distribute,
95
+ all copyright, patent, trademark, and attribution notices from the Source form
96
+ of the Work, excluding those notices that do not pertain to any part of the
97
+ Derivative Works; and
98
+ If the Work includes a "NOTICE" text file as part of its distribution, then any
99
+ Derivative Works that You distribute must include a readable copy of the
100
+ attribution notices contained within such NOTICE file, excluding those notices
101
+ that do not pertain to any part of the Derivative Works, in at least one of the
102
+ following places: within a NOTICE text file distributed as part of the
103
+ Derivative Works; within the Source form or documentation, if provided along
104
+ with the Derivative Works; or, within a display generated by the Derivative
105
+ Works, if and wherever such third-party notices normally appear. The contents of
106
+ the NOTICE file are for informational purposes only and do not modify the
107
+ License. You may add Your own attribution notices within Derivative Works that
108
+ You distribute, alongside or as an addendum to the NOTICE text from the Work,
109
+ provided that such additional attribution notices cannot be construed as
110
+ modifying the License.
111
+ You may add Your own copyright statement to Your modifications and may provide
112
+ additional or different license terms and conditions for use, reproduction, or
113
+ distribution of Your modifications, or for any such Derivative Works as a whole,
114
+ provided Your use, reproduction, and distribution of the Work otherwise complies
115
+ with the conditions stated in this License.
116
+
117
+ 5. Submission of Contributions.
118
+
119
+ Unless You explicitly state otherwise, any Contribution intentionally submitted
120
+ for inclusion in the Work by You to the Licensor shall be under the terms and
121
+ conditions of this License, without any additional terms or conditions.
122
+ Notwithstanding the above, nothing herein shall supersede or modify the terms of
123
+ any separate license agreement you may have executed with Licensor regarding
124
+ such Contributions.
125
+
126
+ 6. Trademarks.
127
+
128
+ This License does not grant permission to use the trade names, trademarks,
129
+ service marks, or product names of the Licensor, except as required for
130
+ reasonable and customary use in describing the origin of the Work and
131
+ reproducing the content of the NOTICE file.
132
+
133
+ 7. Disclaimer of Warranty.
134
+
135
+ Unless required by applicable law or agreed to in writing, Licensor provides the
136
+ Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138
+ including, without limitation, any warranties or conditions of TITLE,
139
+ NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140
+ solely responsible for determining the appropriateness of using or
141
+ redistributing the Work and assume any risks associated with Your exercise of
142
+ permissions under this License.
143
+
144
+ 8. Limitation of Liability.
145
+
146
+ In no event and under no legal theory, whether in tort (including negligence),
147
+ contract, or otherwise, unless required by applicable law (such as deliberate
148
+ and grossly negligent acts) or agreed to in writing, shall any Contributor be
149
+ liable to You for damages, including any direct, indirect, special, incidental,
150
+ or consequential damages of any character arising as a result of this License or
151
+ out of the use or inability to use the Work (including but not limited to
152
+ damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153
+ any and all other commercial damages or losses), even if such Contributor has
154
+ been advised of the possibility of such damages.
155
+
156
+ 9. Accepting Warranty or Additional Liability.
157
+
158
+ While redistributing the Work or Derivative Works thereof, You may choose to
159
+ offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160
+ other liability obligations and/or rights consistent with this License. However,
161
+ in accepting such obligations, You may act only on Your own behalf and on Your
162
+ sole responsibility, not on behalf of any other Contributor, and only if You
163
+ agree to indemnify, defend, and hold each Contributor harmless for any liability
164
+ incurred by, or claims asserted against, such Contributor by reason of your
165
+ accepting any such warranty or additional liability.
166
+
167
+ END OF TERMS AND CONDITIONS
168
+
169
+ APPENDIX: How to apply the Apache License to your work
170
+
171
+ To apply the Apache License to your work, attach the following boilerplate
172
+ notice, with the fields enclosed by brackets "[]" replaced with your own
173
+ identifying information. (Don't include the brackets!) The text should be
174
+ enclosed in the appropriate comment syntax for the file format. We also
175
+ recommend that a file or class name and description of purpose be included on
176
+ the same "printed page" as the copyright notice for easier identification within
177
+ third-party archives.
178
+
179
+ Copyright [yyyy] [name of copyright owner]
180
+
181
+ Licensed under the Apache License, Version 2.0 (the "License");
182
+ you may not use this file except in compliance with the License.
183
+ You may obtain a copy of the License at
184
+
185
+ http://www.apache.org/licenses/LICENSE-2.0
186
+
187
+ Unless required by applicable law or agreed to in writing, software
188
+ distributed under the License is distributed on an "AS IS" BASIS,
189
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190
+ See the License for the specific language governing permissions and
191
+ limitations under the License.
data/README.textile ADDED
@@ -0,0 +1,34 @@
1
+ h1. 粗糙的MONGOID TAG
2
+
3
+ h3. 设计目的:
4
+
5
+ # 不用动脑子想tag的设计
6
+ # 单向对基于tag查询实体的优化
7
+
8
+ h3. 基于以下假设
9
+
10
+ # 根据标签名称,查找实体的情况频繁于根据实体查找tags
11
+ # 实体间不共享一类 tag
12
+
13
+ h3. 用法
14
+
15
+ <ruby>
16
+
17
+ class Model
18
+ include Mongoid::Document
19
+ include EasyMongoidTag
20
+
21
+ field :bname, as: :book_name, type: String
22
+ easy_tags :tests
23
+ end
24
+
25
+ book1 = Model.create(bname: '红楼梦', :tests => ['曹雪芹 ', ' 高 鹗 '])
26
+ book2 = Model.create(bname: '石头记', :tests => ['曹沾', '高 鹗'])
27
+
28
+
29
+ book1.test_tags
30
+ TestTag.find_by(title: '曹雪芹')
31
+ TestTag.search('曹')
32
+
33
+
34
+ </ruby>
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/easy_mongoid_tag/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'easy_mongoid_tag'
6
+ s.version = EasyMongoidTag::VERSION
7
+ s.date = '2013-09-05'
8
+ s.summary = "粗糙的mongid tag"
9
+ s.description = "实现实体和标签间的N2N关系,对基于tag查询实体的单向优化"
10
+ s.authors = ["Wade Xing"]
11
+ s.email = ['iamxingxing@gmail.com']
12
+ s.files = `git ls-files`.split($\)
13
+
14
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+
17
+ s.require_paths = ['lib']
18
+
19
+ s.homepage = 'https://github.com/xingxing/easy_mongoid_tag'
20
+
21
+ s.add_runtime_dependency 'mongoid', '~> 3.1.0'
22
+
23
+ s.add_development_dependency 'rspec', '~> 2.14.1'
24
+ s.add_development_dependency 'mongoid-rspec', '~> 1.9.0'
25
+ s.add_development_dependency 'guard', '~> 1.8.0'
26
+ s.add_development_dependency 'guard-rspec', '~> 3.0.0'
27
+ s.add_development_dependency 'guard-spork', '~> 1.5.1'
28
+ s.add_development_dependency 'terminal-notifier-guard', '~> 1.5.3'
29
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'mongoid'
3
+
4
+ require 'easy_mongoid_tag/tag'
5
+ #require 'mongoid_extensions/extension_field'
@@ -0,0 +1,151 @@
1
+ # -*- coding: utf-8 -*-
2
+ module EasyMongoidTag
3
+
4
+ def self.included mod
5
+ unless mod.included_modules.include?(Mongoid::Document)
6
+ raise(RuntimeError, 'EasyMongoidTag is mixined A non-mongoid_document')
7
+ else
8
+ mod.class_eval do
9
+ extend ClassMethods
10
+
11
+ # 存储 tag 的名字
12
+ class_attribute :tag_items
13
+ self.tag_items = []
14
+
15
+ end
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+
21
+ # 生成 标签field
22
+ # @param[Symbol]
23
+ def easy_tag tag_name
24
+ field_name = Helper.field_name(tag_name)
25
+
26
+ field field_name, type: Array
27
+ self.tag_items << tag_name
28
+ index({ field_name => 1 })
29
+
30
+ tag_class = generate_tag_class(tag_name)
31
+
32
+ self.instance_eval do
33
+ define_method Helper.tags_method_name(tag_name) do
34
+ tag_class.find(*self.send(field_name))
35
+ end
36
+ end
37
+
38
+ before_validation do |doc|
39
+ doc.send("#{field_name}=",
40
+ doc[tag_name].map do |title_or_object_id|
41
+ if title_or_object_id.is_a? Moped::BSON::ObjectId
42
+ title_or_object_id
43
+ else
44
+ title_or_object_id.strip!
45
+ tag = tag_class.where(title: title_or_object_id).first
46
+ if tag
47
+ tag.id
48
+ else
49
+ tag = tag_class.new(title: title_or_object_id)
50
+ tag.save ? tag.id : nil
51
+ end
52
+ end
53
+ end.select(&:present?)) if doc[tag_name]
54
+ end
55
+ end
56
+
57
+ def easy_tags *tag_names
58
+ tag_names.each do |tag_name|
59
+ easy_tag tag_name
60
+ end
61
+ end
62
+
63
+ # 生成标签类
64
+ #
65
+ def generate_tag_class tag_name
66
+
67
+ tag_class_name = Helper.tag_class_name(tag_name)
68
+ field_name = Helper.field_name(tag_name)
69
+
70
+ if Helper.class_existed?(tag_class_name)
71
+ raise(RuntimeError, "Class #{tag_class_name} already existed!")
72
+ return
73
+ else
74
+ # model 类的
75
+ main_class_name = self.name
76
+ Object.const_set(tag_class_name,
77
+ Class.new do
78
+ include Mongoid::Document
79
+ include Mongoid::Timestamps::Created
80
+
81
+ store_in collection: tag_class_name.tableize
82
+
83
+ field :title, type: String
84
+ index({ title: 1 }, { unique: true })
85
+
86
+ define_method main_class_name.downcase.pluralize do
87
+ Object.const_get(main_class_name).where(field_name => self.id)
88
+ end
89
+
90
+ class << self
91
+ def search key_word
92
+ self.any_of(title: /.*#{key_word}.*/)
93
+ end
94
+ end
95
+
96
+ before_validation do |record|
97
+ record.title = record.title.strip
98
+ end
99
+
100
+ after_destroy do |record|
101
+ record.send(main_class_name.downcase.pluralize).each do |model|
102
+ Object.const_get(main_class_name).skip_callback(:validation, :before)
103
+ model.send("#{field_name}=", model.send(field_name).reject{|t| t == record.id } )
104
+ model.save
105
+ Object.const_get(main_class_name).set_callback(:validation, :before)
106
+ end
107
+ end
108
+
109
+ end)
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+ module Helper
116
+
117
+ include ActiveSupport::Concern
118
+
119
+ class << self
120
+
121
+ def field_name tag_name
122
+ tag_name.to_sym
123
+ end
124
+
125
+ def tags_method_name tag_name
126
+ "#{tag_name.to_s.singularize}_tags".to_sym
127
+ end
128
+
129
+ # tags_list_name = 'list_' + tag_name
130
+ def tag_list_name tag_name
131
+ "list_#{tag_name}".to_sym
132
+ end
133
+
134
+ # 标签类的类名
135
+ # @return [String]
136
+ def tag_class_name tag_name
137
+ tag_name.to_s.classify + 'Tag'
138
+ end
139
+
140
+ # 是否已经存在 类
141
+ # @param [ String ] 类名
142
+ def class_existed? class_name
143
+ klass = Module.const_get(class_name)
144
+ return klass.is_a?(Class)
145
+ rescue NameError
146
+ return false
147
+ end
148
+ end
149
+
150
+ end
151
+ end