easy_tags 0.1.0.pre.alpha
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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +3 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +33 -0
- data/.yardopts +1 -0
- data/Appraisals +14 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/MIGRATING_FROM_AATO.MD +41 -0
- data/README.md +344 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/easy_tags.gemspec +33 -0
- data/gemfiles/activerecord_5.0.gemfile +8 -0
- data/gemfiles/activerecord_5.1.gemfile +8 -0
- data/gemfiles/activerecord_5.2.gemfile +8 -0
- data/lib/easy_tags/generators/default.rb +24 -0
- data/lib/easy_tags/options/callback.rb +34 -0
- data/lib/easy_tags/options/collection.rb +28 -0
- data/lib/easy_tags/options/item.rb +41 -0
- data/lib/easy_tags/parsers/default.rb +22 -0
- data/lib/easy_tags/tag.rb +36 -0
- data/lib/easy_tags/tag_list.rb +47 -0
- data/lib/easy_tags/taggable.rb +52 -0
- data/lib/easy_tags/taggable_context.rb +56 -0
- data/lib/easy_tags/taggable_context_methods.rb +56 -0
- data/lib/easy_tags/taggable_methods.rb +109 -0
- data/lib/easy_tags/tagging.rb +34 -0
- data/lib/easy_tags/version.rb +3 -0
- data/lib/easy_tags.rb +74 -0
- data/lib/generators/easy_tags/migration_generator.rb +30 -0
- data/lib/generators/easy_tags/templates/create_tables_migration.rb.erb +17 -0
- metadata +204 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module EasyTags
|
2
|
+
module Options
|
3
|
+
# Represents collection of options
|
4
|
+
class Collection
|
5
|
+
def initialize(options)
|
6
|
+
@options = options.uniq
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [Boolean]
|
10
|
+
def valid?
|
11
|
+
filtered_options.all?(&:valid?)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
def items
|
16
|
+
filtered_options
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def filtered_options
|
22
|
+
@filtered_options ||= @options.to_a.flatten.compact.map do |raw_option|
|
23
|
+
Item.new(raw_option)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module EasyTags
|
2
|
+
module Options
|
3
|
+
# Represents a single option item
|
4
|
+
class Item
|
5
|
+
def initialize(option)
|
6
|
+
@option = option
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [Boolean]
|
10
|
+
def valid?
|
11
|
+
/[@$"]/ !~ name.inspect
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Symbol]
|
15
|
+
def name
|
16
|
+
@name ||= key.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Array<Callback>]
|
20
|
+
def callbacks
|
21
|
+
return [] unless callbacks?
|
22
|
+
|
23
|
+
@option.values.first.map do |type, callback|
|
24
|
+
Callback.new(callback: callback, type: type)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def key
|
31
|
+
return @option.keys.first if callbacks?
|
32
|
+
|
33
|
+
@option
|
34
|
+
end
|
35
|
+
|
36
|
+
def callbacks?
|
37
|
+
@option.is_a?(Hash)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module EasyTags
|
2
|
+
module Parsers
|
3
|
+
# Default parser for [String] -> [Array] conversion
|
4
|
+
class Default
|
5
|
+
class << self
|
6
|
+
# Returns a new TagList using the given tag string.
|
7
|
+
#
|
8
|
+
# @param [String] tag_list_string
|
9
|
+
# @return [Array<String>]
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# EasyTags::Parsers::Default.parse('One , Two, Three')
|
13
|
+
# ['One', 'Two', 'Three']
|
14
|
+
def parse(tag_list_string)
|
15
|
+
return [] if tag_list_string.to_s.empty?
|
16
|
+
|
17
|
+
tag_list_string.to_s.split(/,/).map(&:strip)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module EasyTags
|
2
|
+
# Tag model
|
3
|
+
class Tag < ::ActiveRecord::Base
|
4
|
+
self.table_name = EasyTags.tags_table
|
5
|
+
|
6
|
+
has_many :taggings, dependent: :destroy, class_name: '::EasyTags::Tagging', inverse_of: :tag
|
7
|
+
|
8
|
+
validates_presence_of :name
|
9
|
+
validates_uniqueness_of :name
|
10
|
+
validates_length_of :name, maximum: 255
|
11
|
+
|
12
|
+
after_commit :notify_add, on: :create
|
13
|
+
after_commit :notify_remove, on: :destroy
|
14
|
+
|
15
|
+
# cast object to string
|
16
|
+
def to_s
|
17
|
+
name
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def notify_add
|
23
|
+
ActiveSupport::Notifications.instrument(
|
24
|
+
'easy_tag.tag_added',
|
25
|
+
tag: self
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def notify_remove
|
30
|
+
ActiveSupport::Notifications.instrument(
|
31
|
+
'easy_tag.tag_removed',
|
32
|
+
tag: self
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module EasyTags
|
2
|
+
# Represents a tag list
|
3
|
+
class TagList < SimpleDelegator
|
4
|
+
def initialize(
|
5
|
+
*args,
|
6
|
+
generator: EasyTags.generator,
|
7
|
+
parser: EasyTags.parser
|
8
|
+
)
|
9
|
+
self.generator = generator
|
10
|
+
self.parser = parser
|
11
|
+
super([])
|
12
|
+
|
13
|
+
add(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Add tags to the tag_list. Duplicate or blank tags will be ignored.
|
17
|
+
#
|
18
|
+
# Example:
|
19
|
+
# tag_list.add('Fun', 'Happy')
|
20
|
+
def add(*names)
|
21
|
+
filter(names).each { |filtered_name| push(filtered_name) unless include?(filtered_name) }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Transform the tag_list into a tag string
|
25
|
+
def to_s
|
26
|
+
generator.generate(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Remove item from list
|
30
|
+
#
|
31
|
+
# Example:
|
32
|
+
# tag_list.remove('Issues')
|
33
|
+
def remove(value)
|
34
|
+
__getobj__.delete(value)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_accessor :generator, :parser
|
40
|
+
|
41
|
+
def filter(names)
|
42
|
+
names.to_a.flatten.compact.map do |name|
|
43
|
+
parser.parse(name)
|
44
|
+
end.flatten.compact.uniq
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# rubocop:disable Style/Documentation
|
2
|
+
module EasyTags
|
3
|
+
module Taggable
|
4
|
+
module ClassMethods
|
5
|
+
# rubocop:enable Style/Documentation
|
6
|
+
#
|
7
|
+
# Examples
|
8
|
+
#
|
9
|
+
# easy_tags_on :highlights
|
10
|
+
#
|
11
|
+
# with multiple contexts:
|
12
|
+
#
|
13
|
+
# easy_tags_on :highlights, :tags
|
14
|
+
#
|
15
|
+
# with callbacks:
|
16
|
+
#
|
17
|
+
# easy_tags_on(
|
18
|
+
# highlights: {
|
19
|
+
# after_add: :add_tag_callback, after_remove: ->(tagging) { puts "removed #{tagging.tag.name}" }
|
20
|
+
# }
|
21
|
+
# )
|
22
|
+
#
|
23
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
24
|
+
def easy_tags_on(*tagging_contexts_params)
|
25
|
+
cattr_accessor :tagging_contexts
|
26
|
+
cattr_accessor :tagging_callbacks
|
27
|
+
|
28
|
+
options = Options::Collection.new(tagging_contexts_params.to_a)
|
29
|
+
raise 'invalid options' unless options.valid?
|
30
|
+
|
31
|
+
self.tagging_contexts ||= []
|
32
|
+
self.tagging_callbacks ||= {}
|
33
|
+
|
34
|
+
options.items.each do |option|
|
35
|
+
tagging_contexts.push(option.name) unless tagging_contexts.include?(option.name)
|
36
|
+
tagging_callbacks[option.name] = option.callbacks
|
37
|
+
|
38
|
+
EasyTags::TaggableContextMethods.inject(
|
39
|
+
class_instance: self,
|
40
|
+
context: option.name
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.included(base)
|
48
|
+
base.extend(ClassMethods)
|
49
|
+
EasyTags::TaggableMethods.inject(class_instance: base)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module EasyTags
|
2
|
+
# Handles tag context manipulation
|
3
|
+
class TaggableContext
|
4
|
+
# @param [String, Symbol] context
|
5
|
+
# @param [Proc] refresh_persisted_tags
|
6
|
+
# @param [Proc] on_change
|
7
|
+
def initialize(context:, refresh_persisted_tags:, on_change:)
|
8
|
+
self.context = context
|
9
|
+
self.refresh_persisted_tags = refresh_persisted_tags
|
10
|
+
self.on_change = on_change
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [true, false]
|
14
|
+
def changed?
|
15
|
+
tags.sort != persisted_tags.sort
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [TagList]
|
19
|
+
def tags
|
20
|
+
@tags ||= TagList.new(persisted_tags)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [TagList]
|
24
|
+
def persisted_tags
|
25
|
+
@persisted_tags ||= TagList.new(refresh_persisted_tags.call)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [String, Symbol] value
|
29
|
+
# @return [TagList]
|
30
|
+
def update(value)
|
31
|
+
@tags = TagList.new(value)
|
32
|
+
|
33
|
+
on_change.call(self) if changed?
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [TagList]
|
37
|
+
def new_tags
|
38
|
+
tags - persisted_tags
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [TagList]
|
42
|
+
def removed_tags
|
43
|
+
persisted_tags - tags
|
44
|
+
end
|
45
|
+
|
46
|
+
# clear memoized info and force a refresh
|
47
|
+
def refresh
|
48
|
+
@tags = nil
|
49
|
+
@persisted_tags = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_accessor :context, :refresh_persisted_tags, :on_change
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module EasyTags
|
2
|
+
# Handles injecting of the dynamic context related methods
|
3
|
+
# Example:
|
4
|
+
# easy_tags_on :bees
|
5
|
+
#
|
6
|
+
# # will create:
|
7
|
+
#
|
8
|
+
# has_many :bees_taggings
|
9
|
+
# has_many :bees_tags
|
10
|
+
#
|
11
|
+
# def bees
|
12
|
+
# def bees=
|
13
|
+
# def bees_list
|
14
|
+
# def bees_list=
|
15
|
+
class TaggableContextMethods
|
16
|
+
class << self
|
17
|
+
def inject(class_instance:, context:)
|
18
|
+
class_instance.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
19
|
+
has_many(
|
20
|
+
:#{context}_taggings, -> { includes(:tag).where(context: :#{context}) },
|
21
|
+
as: :taggable,
|
22
|
+
class_name: 'EasyTags::Tagging',
|
23
|
+
dependent: :destroy
|
24
|
+
)
|
25
|
+
|
26
|
+
has_many(
|
27
|
+
:#{context}_tags,
|
28
|
+
class_name: 'EasyTags::Tag',
|
29
|
+
through: :#{context}_taggings,
|
30
|
+
source: :tag
|
31
|
+
)
|
32
|
+
|
33
|
+
attribute :#{context}_list, ActiveModel::Type::Value.new
|
34
|
+
|
35
|
+
def #{context}
|
36
|
+
_taggable_context(:#{context}).tags
|
37
|
+
end
|
38
|
+
|
39
|
+
def #{context}=(value)
|
40
|
+
_taggable_context(:#{context}).update(value)
|
41
|
+
#{context}
|
42
|
+
end
|
43
|
+
|
44
|
+
def #{context}_list
|
45
|
+
_taggable_context(:#{context}).tags.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def #{context}_list=(value)
|
49
|
+
_taggable_context(:#{context}).update(value)
|
50
|
+
#{context}_list
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module EasyTags
|
2
|
+
# Taggable instance methods
|
3
|
+
module TaggableMethods
|
4
|
+
class << self
|
5
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
6
|
+
def inject(class_instance:)
|
7
|
+
# rubocop:disable Metrics/BlockLength
|
8
|
+
class_instance.class_eval do
|
9
|
+
has_many(
|
10
|
+
:taggings,
|
11
|
+
as: :taggable,
|
12
|
+
dependent: :destroy,
|
13
|
+
class_name: '::EasyTags::Tagging',
|
14
|
+
inverse_of: :taggable
|
15
|
+
)
|
16
|
+
|
17
|
+
has_many(
|
18
|
+
:base_tags,
|
19
|
+
through: :taggings,
|
20
|
+
source: :tag,
|
21
|
+
class_name: '::EasyTags::Tag',
|
22
|
+
inverse_of: :tag
|
23
|
+
)
|
24
|
+
|
25
|
+
after_save :_update_taggings, :_refresh_tagging
|
26
|
+
after_find :_refresh_tagging
|
27
|
+
|
28
|
+
# override ActiveRecord::Persistence#reload
|
29
|
+
# to refresh tags each time the model instance gets reloaded
|
30
|
+
def reload
|
31
|
+
_refresh_tagging
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_accessor :_taggable_contexts
|
38
|
+
|
39
|
+
def _taggable_contexts
|
40
|
+
@_taggable_contexts ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def _update_taggings
|
44
|
+
tagging_contexts.each do |context|
|
45
|
+
context_tags = _taggable_context(context)
|
46
|
+
|
47
|
+
next unless context_tags.changed?
|
48
|
+
|
49
|
+
context_tags.new_tags.each do |tag_name|
|
50
|
+
tag = Tag.find_or_create_by!(name: tag_name)
|
51
|
+
taggings.create!(context: context, tag: tag)
|
52
|
+
end
|
53
|
+
|
54
|
+
taggings
|
55
|
+
.joins(:tag)
|
56
|
+
.where(context: context)
|
57
|
+
.where(Tag.table_name => { name: context_tags.removed_tags })
|
58
|
+
.destroy_all
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def _refresh_tagging
|
63
|
+
tagging_contexts.each do |context|
|
64
|
+
_taggable_context(context).refresh
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def _mark_dirty(context:, taggable_context:)
|
69
|
+
write_attribute("#{context}_list", taggable_context.tags.to_s)
|
70
|
+
set_attribute_was("#{context}_list", taggable_context.persisted_tags.to_s)
|
71
|
+
attribute_will_change!("#{context}_list")
|
72
|
+
end
|
73
|
+
|
74
|
+
def _taggable_context(context)
|
75
|
+
_taggable_contexts[context] ||= TaggableContext.new(
|
76
|
+
context: context,
|
77
|
+
refresh_persisted_tags: lambda {
|
78
|
+
taggings.joins(:tag).where(context: context).pluck(:name)
|
79
|
+
},
|
80
|
+
on_change: lambda { |tag_context|
|
81
|
+
_mark_dirty(context: context, taggable_context: tag_context)
|
82
|
+
}
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def _notify_tag_change(type:, tagging:)
|
87
|
+
callbacks_for_type = tagging_callbacks[tagging.context.to_sym].select do |callback|
|
88
|
+
callback.type == type
|
89
|
+
end
|
90
|
+
|
91
|
+
callbacks_for_type.each do |callback|
|
92
|
+
callback.run(taggable: self, tagging: tagging)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def _notify_tag_add(tagging)
|
97
|
+
_notify_tag_change(type: :after_add, tagging: tagging)
|
98
|
+
end
|
99
|
+
|
100
|
+
def _notify_tag_remove(tagging)
|
101
|
+
_notify_tag_change(type: :after_remove, tagging: tagging)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
# rubocop:enable Metrics/BlockLength
|
105
|
+
end
|
106
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module EasyTags
|
2
|
+
# Tagging model
|
3
|
+
class Tagging < ::ActiveRecord::Base
|
4
|
+
self.table_name = EasyTags.taggings_table
|
5
|
+
|
6
|
+
belongs_to :tag, class_name: '::EasyTags::Tag', optional: false, inverse_of: :taggings
|
7
|
+
belongs_to :taggable, polymorphic: true, optional: false, inverse_of: :taggings
|
8
|
+
|
9
|
+
validates_uniqueness_of :tag_id, scope: %i[taggable_type taggable_id context]
|
10
|
+
|
11
|
+
after_commit :notify_add, on: :create
|
12
|
+
after_commit :notify_remove, on: :destroy
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def notify_add
|
17
|
+
ActiveSupport::Notifications.instrument(
|
18
|
+
"easy_tag.tagging_added.#{taggable_type.to_s.tableize}.#{context}",
|
19
|
+
tagging: self
|
20
|
+
)
|
21
|
+
|
22
|
+
taggable.send(:_notify_tag_add, self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def notify_remove
|
26
|
+
ActiveSupport::Notifications.instrument(
|
27
|
+
"easy_tag.tagging_removed.#{taggable_type.to_s.tableize}.#{context}",
|
28
|
+
tagging: self
|
29
|
+
)
|
30
|
+
|
31
|
+
taggable.send(:_notify_tag_remove, self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/easy_tags.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'active_support/dependencies/autoload'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
# rubocop:disable Style/Documentation
|
5
|
+
module EasyTags
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :Tag, 'easy_tags/tag'
|
9
|
+
autoload :TaggableMethods, 'easy_tags/taggable_methods'
|
10
|
+
autoload :TaggableContextMethods, 'easy_tags/taggable_context_methods'
|
11
|
+
autoload :TaggableContext, 'easy_tags/taggable_context'
|
12
|
+
autoload :Taggable, 'easy_tags/taggable'
|
13
|
+
autoload :Tagging, 'easy_tags/tagging'
|
14
|
+
autoload :TagList, 'easy_tags/tag_list'
|
15
|
+
autoload :VERSION, 'easy_tags/version'
|
16
|
+
|
17
|
+
module Parsers
|
18
|
+
autoload :Default, 'easy_tags/parsers/default'
|
19
|
+
end
|
20
|
+
|
21
|
+
module Generators
|
22
|
+
autoload :Default, 'easy_tags/generators/default'
|
23
|
+
end
|
24
|
+
|
25
|
+
module Options
|
26
|
+
autoload :Callback, 'easy_tags/options/callback'
|
27
|
+
autoload :Item, 'easy_tags/options/item'
|
28
|
+
autoload :Collection, 'easy_tags/options/collection'
|
29
|
+
end
|
30
|
+
# rubocop:enable Style/Documentation
|
31
|
+
|
32
|
+
# handle lib configuration options
|
33
|
+
#
|
34
|
+
# Example
|
35
|
+
#
|
36
|
+
# EasyTags.setup do |config|
|
37
|
+
# config.tags_table = :tags
|
38
|
+
# config.taggings_table = :taggings
|
39
|
+
# config.parser = EasyTags::Parsers::Default
|
40
|
+
# config.generator = EasyTags::Generators::Default
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
class Configuration
|
44
|
+
OPTIONS = %i[
|
45
|
+
tags_table
|
46
|
+
taggings_table
|
47
|
+
parser
|
48
|
+
generator
|
49
|
+
].freeze
|
50
|
+
|
51
|
+
attr_accessor(
|
52
|
+
*OPTIONS
|
53
|
+
)
|
54
|
+
|
55
|
+
def initialize
|
56
|
+
self.tags_table = :tags
|
57
|
+
self.taggings_table = :taggings
|
58
|
+
self.parser = Parsers::Default
|
59
|
+
self.generator = Generators::Default
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
def configuration
|
65
|
+
@configuration ||= Configuration.new
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup
|
69
|
+
yield(configuration)
|
70
|
+
end
|
71
|
+
|
72
|
+
delegate(*Configuration::OPTIONS, to: :configuration)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module EasyTags
|
4
|
+
module Generators
|
5
|
+
# generates database migration
|
6
|
+
#
|
7
|
+
# Usage
|
8
|
+
# rails g easy_tags:migration
|
9
|
+
#
|
10
|
+
class MigrationGenerator < Rails::Generators::Base
|
11
|
+
include ActiveRecord::Generators::Migration
|
12
|
+
|
13
|
+
source_root File.expand_path('templates', __dir__)
|
14
|
+
|
15
|
+
def copy_migrations
|
16
|
+
migration_template(
|
17
|
+
'create_tables_migration.rb.erb',
|
18
|
+
"#{db_migrate_path}/easy_tags_create_tables.rb",
|
19
|
+
migration_version: migration_version
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def migration_version
|
26
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class EasyTagsCreateTables < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def change
|
3
|
+
create_table <%= ":#{EasyTags.tags_table}" %> do |t|
|
4
|
+
t.string :name, index: true
|
5
|
+
|
6
|
+
t.timestamps null: false
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table <%= ":#{EasyTags.taggings_table}" %> do |t|
|
10
|
+
t.references :tag, foreign_key: { to_table: <%= ":#{EasyTags.tags_table}" %> }, null: false, index: true
|
11
|
+
t.references :taggable, polymorphic: true, index: true, null: false
|
12
|
+
t.string :context, null: false, index: true
|
13
|
+
|
14
|
+
t.datetime :created_at, null: false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|