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