rails_best_practices 0.10.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -0
- data/assets/result.html.haml +1 -1
- data/lib/rails_best_practices.rb +5 -3
- data/lib/rails_best_practices/core.rb +1 -1
- data/lib/rails_best_practices/core/check.rb +9 -12
- data/lib/rails_best_practices/core/checking_visitor.rb +9 -6
- data/lib/rails_best_practices/core/model_associations.rb +1 -1
- data/lib/rails_best_practices/core/nil.rb +5 -1
- data/lib/rails_best_practices/core/runner.rb +5 -5
- data/lib/rails_best_practices/core_ext/sexp.rb +688 -0
- data/lib/rails_best_practices/prepares/mailer_prepare.rb +4 -5
- data/lib/rails_best_practices/prepares/model_prepare.rb +16 -26
- data/lib/rails_best_practices/prepares/schema_prepare.rb +11 -17
- data/lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb +24 -75
- data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +39 -113
- data/lib/rails_best_practices/reviews/dry_bundler_in_capistrano_review.rb +6 -16
- data/lib/rails_best_practices/reviews/isolate_seed_data_review.rb +16 -32
- data/lib/rails_best_practices/reviews/keep_finders_on_their_own_model_review.rb +11 -20
- data/lib/rails_best_practices/reviews/law_of_demeter_review.rb +7 -28
- data/lib/rails_best_practices/reviews/move_code_into_controller_review.rb +16 -14
- data/lib/rails_best_practices/reviews/move_code_into_helper_review.rb +10 -28
- data/lib/rails_best_practices/reviews/move_code_into_model_review.rb +12 -11
- data/lib/rails_best_practices/reviews/move_finder_to_named_scope_review.rb +13 -24
- data/lib/rails_best_practices/reviews/move_model_logic_into_model_review.rb +9 -9
- data/lib/rails_best_practices/reviews/needless_deep_nesting_review.rb +24 -68
- data/lib/rails_best_practices/reviews/not_use_default_route_review.rb +15 -22
- data/lib/rails_best_practices/reviews/overuse_route_customizations_review.rb +31 -91
- data/lib/rails_best_practices/reviews/remove_empty_helpers_review.rb +4 -2
- data/lib/rails_best_practices/reviews/replace_complex_creation_with_factory_method_review.rb +20 -18
- data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +5 -3
- data/lib/rails_best_practices/reviews/review.rb +8 -37
- data/lib/rails_best_practices/reviews/simplify_render_in_controllers_review.rb +10 -6
- data/lib/rails_best_practices/reviews/simplify_render_in_views_review.rb +9 -6
- data/lib/rails_best_practices/reviews/use_before_filter_review.rb +14 -72
- data/lib/rails_best_practices/reviews/use_model_association_review.rb +19 -31
- data/lib/rails_best_practices/reviews/use_multipart_alternative_as_content_type_of_email_review.rb +5 -5
- data/lib/rails_best_practices/reviews/use_observer_review.rb +22 -40
- data/lib/rails_best_practices/reviews/use_query_attribute_review.rb +34 -39
- data/lib/rails_best_practices/reviews/use_say_with_time_in_migrations_review.rb +14 -38
- data/lib/rails_best_practices/reviews/use_scope_access_review.rb +13 -44
- data/lib/rails_best_practices/version.rb +1 -1
- data/spec/rails_best_practices/core/check_spec.rb +5 -5
- data/spec/rails_best_practices/core/checking_visitor_spec.rb +4 -4
- data/spec/rails_best_practices/core/model_associations_spec.rb +4 -4
- data/spec/rails_best_practices/core/nil_spec.rb +7 -1
- data/spec/rails_best_practices/core_ext/sexp_spec.rb +430 -0
- data/spec/rails_best_practices/prepares/model_prepare_spec.rb +12 -12
- data/spec/rails_best_practices/prepares/schema_prepare_spec.rb +6 -6
- data/spec/rails_best_practices/reviews/move_code_into_controller_review_spec.rb +14 -2
- data/spec/rails_best_practices/reviews/move_code_into_helper_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/needless_deep_nesting_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb +15 -1
- data/spec/rails_best_practices/reviews/simplify_render_in_controllers_review_spec.rb +3 -3
- data/spec/rails_best_practices/reviews/use_query_attribute_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/use_say_with_time_in_migrations_review_spec.rb +1 -1
- data/spec/rails_best_practices/reviews/use_scope_access_review_spec.rb +4 -4
- data/spec/rails_best_practices_spec.rb +1 -3
- data/spec/spec_helper.rb +4 -0
- metadata +6 -8
- data/lib/rails_best_practices/core/visitable_sexp.rb +0 -444
- data/spec/rails_best_practices/core/visitable_sexp_spec.rb +0 -272
- data/spec/rails_best_practices/reviews/review_spec.rb +0 -11
@@ -15,17 +15,16 @@ module RailsBestPractices
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def initialize
|
18
|
-
@mailers =
|
18
|
+
@mailers = Prepares.mailers
|
19
19
|
end
|
20
20
|
|
21
21
|
# check class node.
|
22
22
|
#
|
23
23
|
# if it is a subclass of ActionMailer::Base,
|
24
24
|
# then remember its class name.
|
25
|
-
def start_class(
|
26
|
-
if
|
27
|
-
@mailers <<
|
28
|
-
Prepares.mailers = @mailers
|
25
|
+
def start_class(node)
|
26
|
+
if "ActionMailer::Base" == node.base_class.to_s
|
27
|
+
@mailers << node.class_name.to_s
|
29
28
|
end
|
30
29
|
end
|
31
30
|
end
|
@@ -5,9 +5,10 @@ module RailsBestPractices
|
|
5
5
|
module Prepares
|
6
6
|
# Remember the model associations.
|
7
7
|
class ModelPrepare < Core::Check
|
8
|
+
ASSOCIATION_METHODS = %w(belongs_to has_one has_many has_and_belongs_to_many)
|
8
9
|
|
9
10
|
def interesting_nodes
|
10
|
-
[:class, :
|
11
|
+
[:class, :command]
|
11
12
|
end
|
12
13
|
|
13
14
|
def interesting_files
|
@@ -15,23 +16,17 @@ module RailsBestPractices
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def initialize
|
18
|
-
@models =
|
19
|
-
@model_associations =
|
19
|
+
@models = Prepares.models
|
20
|
+
@model_associations = Prepares.model_associations
|
20
21
|
end
|
21
22
|
|
22
23
|
# check class node to remember the last class name.
|
23
|
-
def start_class(
|
24
|
-
@last_klazz
|
24
|
+
def start_class(node)
|
25
|
+
@last_klazz= node.class_name.to_s
|
25
26
|
@models << @last_klazz
|
26
27
|
end
|
27
28
|
|
28
|
-
#
|
29
|
-
def end_class(class_node)
|
30
|
-
Prepares.models = @models
|
31
|
-
Prepares.model_associations = @model_associations
|
32
|
-
end
|
33
|
-
|
34
|
-
# check call node to remember all assoications.
|
29
|
+
# check command node to remember all assoications.
|
35
30
|
#
|
36
31
|
# the remembered association names (@associations) are like
|
37
32
|
# {
|
@@ -42,26 +37,21 @@ module RailsBestPractices
|
|
42
37
|
# "milestones => {:has_many" => "Milestone"}
|
43
38
|
# }
|
44
39
|
# }
|
45
|
-
def
|
46
|
-
remember_association(node) if
|
40
|
+
def start_command(node)
|
41
|
+
remember_association(node) if ASSOCIATION_METHODS.include? node.message.to_s
|
47
42
|
end
|
48
43
|
|
49
44
|
# remember associations, with class to association names.
|
50
|
-
def remember_association(
|
51
|
-
association_meta =
|
52
|
-
association_name =
|
53
|
-
arguments_node =
|
54
|
-
if arguments_node && :
|
55
|
-
|
56
|
-
association_class = arguments_node[index + 1].to_s if index
|
45
|
+
def remember_association(node)
|
46
|
+
association_meta = node.message.to_s
|
47
|
+
association_name = node.arguments.all[0].to_s
|
48
|
+
arguments_node = node.arguments.all[1]
|
49
|
+
if arguments_node && :bare_assoc_hash == arguments_node.sexp_type
|
50
|
+
association_class = arguments_node.hash_value("class_name").to_s
|
57
51
|
end
|
52
|
+
association_class ||= association_name.classify
|
58
53
|
@model_associations.add_association(@last_klazz, association_name, association_meta, association_class)
|
59
54
|
end
|
60
|
-
|
61
|
-
# default rails association methods.
|
62
|
-
def association_methods
|
63
|
-
[:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
|
64
|
-
end
|
65
55
|
end
|
66
56
|
end
|
67
57
|
end
|
@@ -6,10 +6,10 @@ module RailsBestPractices
|
|
6
6
|
# Remember the model attributes.
|
7
7
|
class SchemaPrepare < Core::Check
|
8
8
|
# all attribute types
|
9
|
-
ATTRIBUTE_TYPES =
|
9
|
+
ATTRIBUTE_TYPES = %w(integer float boolean string text date time datetime binary)
|
10
10
|
|
11
11
|
def interesting_nodes
|
12
|
-
[:
|
12
|
+
[:command, :command_call]
|
13
13
|
end
|
14
14
|
|
15
15
|
def interesting_files
|
@@ -17,26 +17,20 @@ module RailsBestPractices
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def initialize
|
20
|
-
@model_attributes =
|
20
|
+
@model_attributes = Prepares.model_attributes
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
when :create_table
|
27
|
-
@last_klazz = call_node.arguments[1].to_s.classify
|
28
|
-
when *ATTRIBUTE_TYPES
|
29
|
-
attribute_name = call_node.arguments[1].to_s
|
30
|
-
@model_attributes.add_attribute(@last_klazz, attribute_name, call_node.message)
|
31
|
-
else
|
32
|
-
# nothing to do
|
23
|
+
def start_command(node)
|
24
|
+
if "create_table" == node.message.to_s
|
25
|
+
@last_klazz = node.arguments.all[0].to_s.classify
|
33
26
|
end
|
34
27
|
end
|
35
28
|
|
36
|
-
#
|
37
|
-
def
|
38
|
-
if
|
39
|
-
|
29
|
+
# check command_call node to remember the model attributes.
|
30
|
+
def start_command_call(node)
|
31
|
+
if ATTRIBUTE_TYPES.include? node.message.to_s
|
32
|
+
attribute_name = node.arguments.all[0].to_s
|
33
|
+
@model_attributes.add_attribute(@last_klazz, attribute_name, node.message.to_s)
|
40
34
|
end
|
41
35
|
end
|
42
36
|
end
|
@@ -13,15 +13,7 @@ module RailsBestPractices
|
|
13
13
|
# check method define nodes in all controller files,
|
14
14
|
# if there are more than one [] method calls with the same subject and arguments,
|
15
15
|
# but assigned to one model's different attribute.
|
16
|
-
# and after these method calls, there is a save method call for that model,
|
17
|
-
#
|
18
|
-
# def create
|
19
|
-
# @user = User.new(params[:user])
|
20
|
-
# @user.first_name = params[:full_name].split(' ', 2).first
|
21
|
-
# @user.last_name = params[:full_name].split(' ', 2).last
|
22
|
-
# @user.save
|
23
|
-
# end
|
24
|
-
#
|
16
|
+
# and after these method calls, there is a save method call for that model,
|
25
17
|
# then the model needs to add a virtual attribute.
|
26
18
|
class AddModelVirtualAttributeReview < Review
|
27
19
|
def url
|
@@ -29,7 +21,7 @@ module RailsBestPractices
|
|
29
21
|
end
|
30
22
|
|
31
23
|
def interesting_nodes
|
32
|
-
[:
|
24
|
+
[:def]
|
33
25
|
end
|
34
26
|
|
35
27
|
def interesting_files
|
@@ -40,89 +32,46 @@ module RailsBestPractices
|
|
40
32
|
#
|
41
33
|
# it will check every attribute assignment nodes and call node of message :save or :save!, if
|
42
34
|
#
|
43
|
-
# 1. there are more than one arguments who contain
|
44
|
-
# @user.first_name = params[:full_name].split(' ').first
|
45
|
-
# @user.last_name = params[:full_name].split(' ').last
|
35
|
+
# 1. there are more than one arguments who contain array reference node in the right value of assignment nodes,
|
46
36
|
# 2. the messages of attribute assignment nodes housld be different (:first_name= , :last_name=)
|
47
37
|
# 3. the argument of call nodes with message :[] should be same (:full_name)
|
48
38
|
# 4. there should be a call node with message :save or :save! after attribute assignment nodes
|
49
|
-
# @user.save
|
50
39
|
# 5. and the subject of save or save! call node should be the same with the subject of attribute assignment nodes
|
51
40
|
#
|
52
41
|
# then the attribute assignment nodes can add model virtual attribute instead.
|
53
|
-
def
|
54
|
-
@
|
42
|
+
def start_def(node)
|
43
|
+
@assignments = {}
|
55
44
|
node.recursive_children do |child|
|
56
|
-
case child.
|
57
|
-
when :
|
58
|
-
|
45
|
+
case child.sexp_type
|
46
|
+
when :assign
|
47
|
+
assign(child)
|
59
48
|
when :call
|
60
49
|
call_assignment(child)
|
61
|
-
else
|
62
50
|
end
|
63
51
|
end
|
64
52
|
end
|
65
53
|
|
66
54
|
private
|
67
|
-
# check an attribute assignment node, if there is a
|
55
|
+
# check an attribute assignment node, if there is a array reference node in the right value of assignment node,
|
68
56
|
# then remember this attribute assignment.
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
# ),
|
78
|
-
# :first,
|
79
|
-
# s(:arglist)
|
80
|
-
# )
|
81
|
-
# )
|
82
|
-
# )
|
83
|
-
#
|
84
|
-
# The remember attribute assignments (@attrasgns) are as follows
|
85
|
-
#
|
86
|
-
# {
|
87
|
-
# s(:ivar, :@user) =>
|
88
|
-
# [{
|
89
|
-
# :message=>:first_name=,
|
90
|
-
# :arguments=>s(:call, s(:call, nil, :params, s(:arglist)), :[], s(:arglist, s(:lit, :full_name)))
|
91
|
-
# }]
|
92
|
-
# }
|
93
|
-
def attribute_assignment(node)
|
94
|
-
subject = node.subject
|
95
|
-
arguments_node = node.arguments.grep_node(:message => :[])
|
96
|
-
return if subject.nil? or arguments_node.nil?
|
97
|
-
attrasgns(subject) << {:message => node.message, :arguments => arguments_node}
|
57
|
+
def assign(node)
|
58
|
+
left_value = node.left_value
|
59
|
+
right_value = node.right_value
|
60
|
+
return unless :field == left_value.sexp_type && :call == right_value.sexp_type
|
61
|
+
aref_node = right_value.grep_node(:sexp_type => :aref)
|
62
|
+
if aref_node
|
63
|
+
assignments(left_value.subject.to_s) << {:message => left_value.message.to_s, :arguments => aref_node.to_s}
|
64
|
+
end
|
98
65
|
end
|
99
66
|
|
100
|
-
# check a call node with message
|
67
|
+
# check a call node with message "save" or "save!",
|
101
68
|
# if there exists an attribute assignment for the subject of this call node,
|
102
69
|
# and if the arguments of this attribute assignments has duplicated entries (different message and same arguments),
|
103
70
|
# then this node needs to add a virtual attribute.
|
104
|
-
#
|
105
|
-
# e.g. this is @attrasgns
|
106
|
-
# {
|
107
|
-
# s(:ivar, :@user)=>
|
108
|
-
# [{
|
109
|
-
# :message=>:first_name=,
|
110
|
-
# :arguments=>s(:call, s(:call, nil, :params, s(:arglist)), :[], s(:arglist, s(:lit, :full_name)))
|
111
|
-
# }, {
|
112
|
-
# :message=>:last_name=,
|
113
|
-
# :arguments=>s(:call, s(:call, nil, :params, s(:arglist)), :[], s(:arglist, s(:lit, :full_name)))
|
114
|
-
# }]
|
115
|
-
# }
|
116
|
-
# and this is the call node
|
117
|
-
# s(:call, s(:ivar, :@user), :save, s(:arglist))
|
118
|
-
#
|
119
|
-
# The message of call node is :save,
|
120
|
-
# and the key of @attrasgns is the same as the subject of call node,
|
121
|
-
# and the value of @aatrasgns has different message and same arguments.
|
122
71
|
def call_assignment(node)
|
123
|
-
if [
|
124
|
-
subject = node.subject
|
125
|
-
add_error "add model virtual attribute (for #{subject})" if params_dup?(
|
72
|
+
if ["save", "save!"].include? node.message.to_s
|
73
|
+
subject = node.subject.to_s
|
74
|
+
add_error "add model virtual attribute (for #{subject})" if params_dup?(assignments(subject).collect {|h| h[:arguments]})
|
126
75
|
end
|
127
76
|
end
|
128
77
|
|
@@ -132,9 +81,9 @@ module RailsBestPractices
|
|
132
81
|
!nodes.dups.empty?
|
133
82
|
end
|
134
83
|
|
135
|
-
# get the
|
136
|
-
def
|
137
|
-
@
|
84
|
+
# get the assignments of subject.
|
85
|
+
def assignments(subject)
|
86
|
+
@assignments[subject] ||= []
|
138
87
|
end
|
139
88
|
end
|
140
89
|
end
|
@@ -10,12 +10,12 @@ module RailsBestPractices
|
|
10
10
|
# Implementation:
|
11
11
|
#
|
12
12
|
# Review process:
|
13
|
-
# only check the
|
14
|
-
# if the subject of
|
15
|
-
# if the subject of
|
16
|
-
# if the sujbect of
|
17
|
-
# if the subject of
|
18
|
-
# after all of these, at the end of
|
13
|
+
# only check the command and command_calls nodes and at the end of program node in db/schema file,
|
14
|
+
# if the subject of command node is "create_table", then remember the table names
|
15
|
+
# if the subject of command_call node is "integer" and suffix with id, then remember it as foreign key
|
16
|
+
# if the sujbect of command_call node is "string", the name of it is _type suffixed and there is an integer column _id suffixed, then remember it as polymorphic foreign key
|
17
|
+
# if the subject of command node is "add_index", then remember the index columns
|
18
|
+
# after all of these, at the end of program node
|
19
19
|
#
|
20
20
|
# ActiveRecord::Schema.define(:version => 20101201111111) do
|
21
21
|
# ......
|
@@ -29,7 +29,7 @@ module RailsBestPractices
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def interesting_nodes
|
32
|
-
[:
|
32
|
+
[:command, :command_call, :program]
|
33
33
|
end
|
34
34
|
|
35
35
|
def interesting_files
|
@@ -43,83 +43,46 @@ module RailsBestPractices
|
|
43
43
|
@table_nodes = {}
|
44
44
|
end
|
45
45
|
|
46
|
-
# check
|
46
|
+
# check command_call node.
|
47
47
|
#
|
48
|
-
# if the message of
|
49
|
-
# then remember
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
# if the message of command_call node is "create_table", then remember the table name.
|
49
|
+
# if the message of command_call node is "add_index", then remember it as index columns.
|
50
|
+
def start_command_call(node)
|
51
|
+
case node.message.to_s
|
52
|
+
when "integer", "string"
|
53
|
+
remember_foreign_key_columns(node)
|
54
|
+
else
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# check command node.
|
54
59
|
#
|
55
|
-
# if the message of
|
60
|
+
# if the message of command node is "integer",
|
56
61
|
# then remember it as a foreign key of last create table name.
|
57
62
|
#
|
58
|
-
# if the message of
|
63
|
+
# if the message of command node is "type" and the name of argument is _type suffixed,
|
59
64
|
# then remember it with _id suffixed column as polymorphic foreign key.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
# {
|
64
|
-
# "taggings" =>
|
65
|
-
# ["tag_id", ["taggable_id", "taggable_type"]]
|
66
|
-
# }
|
67
|
-
#
|
68
|
-
# if the message of call node is :add_index,
|
69
|
-
# then remember it as index columns (@index_columns) like
|
70
|
-
#
|
71
|
-
# {
|
72
|
-
# "comments" =>
|
73
|
-
# ["post_id", "user_id"]
|
74
|
-
# }
|
75
|
-
def start_call(node)
|
76
|
-
case node.message
|
77
|
-
when :create_table
|
65
|
+
def start_command(node)
|
66
|
+
case node.message.to_s
|
67
|
+
when "create_table"
|
78
68
|
remember_table_nodes(node)
|
79
|
-
when
|
80
|
-
remember_foreign_key_columns(node)
|
81
|
-
when :add_index
|
69
|
+
when "add_index"
|
82
70
|
remember_index_columns(node)
|
83
|
-
else
|
84
71
|
end
|
85
72
|
end
|
86
73
|
|
87
|
-
# check at the end of
|
88
|
-
#
|
89
|
-
# s(:iter,
|
90
|
-
# s(:call,
|
91
|
-
# s(:colon2, s(:const, :ActiveRecord), :Schema),
|
92
|
-
# :define,
|
93
|
-
# s(:arglist, s(:hash, s(:lit, :version), s(:lit, 20100603080629)))
|
94
|
-
# ),
|
95
|
-
# nil,
|
96
|
-
# s(:iter,
|
97
|
-
# s(:call, nil, :create_table,
|
98
|
-
# s(:arglist, s(:str, "comments"), s(:hash, s(:lit, :force), s(:true)))
|
99
|
-
# ),
|
100
|
-
# s(:lasgn, :t),
|
101
|
-
# s(:block,
|
102
|
-
# s(:call, s(:lvar, :t), :string, s(:arglist, s(:str, "content")))
|
103
|
-
# )
|
104
|
-
# )
|
105
|
-
# )
|
106
|
-
#
|
107
|
-
# if the subject of iter node is with subject ActiveRecord::Schema,
|
108
|
-
# it means we have completed the foreign keys and index columns parsing,
|
109
|
-
# then we compare foreign keys and index columns.
|
74
|
+
# check at the end of program node.
|
110
75
|
#
|
76
|
+
# compare foreign keys and index columns,
|
111
77
|
# if there are any foreign keys not existed in index columns,
|
112
78
|
# then we should add db index for that foreign keys.
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
if indexed?(table, column)
|
121
|
-
add_error "always add db index (#{table} => [#{Array(column).join(', ')}])", table_node.file, table_node.line
|
122
|
-
end
|
79
|
+
def end_program(node)
|
80
|
+
remove_only_type_foreign_keys
|
81
|
+
@foreign_keys.each do |table, foreign_key|
|
82
|
+
table_node = @table_nodes[table]
|
83
|
+
foreign_key.each do |column|
|
84
|
+
if indexed?(table, column)
|
85
|
+
add_error "always add db index (#{table} => [#{Array(column).join(', ')}])", table_node.file, table_node.line
|
123
86
|
end
|
124
87
|
end
|
125
88
|
end
|
@@ -127,62 +90,25 @@ module RailsBestPractices
|
|
127
90
|
|
128
91
|
private
|
129
92
|
# remember the node as index columns
|
130
|
-
#
|
131
|
-
# s(:call, nil, :add_index,
|
132
|
-
# s(:arglist,
|
133
|
-
# s(:str, "comments"),
|
134
|
-
# s(:array, s(:str, "post_id")),
|
135
|
-
# s(:hash, s(:lit, :name), s(:str, "index_comments_on_post_id"))
|
136
|
-
# )
|
137
|
-
# )
|
138
|
-
#
|
139
|
-
# the remember index columns are like
|
140
|
-
# {
|
141
|
-
# "comments" =>
|
142
|
-
# ["post_id", "user_id"]
|
143
|
-
# }
|
144
93
|
def remember_index_columns(node)
|
145
|
-
table_name = node.arguments[
|
146
|
-
index_column =
|
94
|
+
table_name = node.arguments.all[0].to_s
|
95
|
+
index_column = node.arguments.all[1].to_object
|
147
96
|
|
148
97
|
@index_columns[table_name] ||= []
|
149
|
-
@index_columns[table_name] <<
|
98
|
+
@index_columns[table_name] << index_column
|
150
99
|
end
|
151
100
|
|
152
101
|
# remember table nodes
|
153
|
-
#
|
154
|
-
# if the node is
|
155
|
-
#
|
156
|
-
# s(:call, nil, :create_table,
|
157
|
-
# s(:arglist, s(:str, "comments"), s(:hash, s(:lit, :force), s(:true))))
|
158
|
-
#
|
159
|
-
# then the table nodes will be
|
160
|
-
#
|
161
|
-
# {
|
162
|
-
# "comments" =>
|
163
|
-
# s(:call, nil, :create_table, s(:arglist, s(:str, "comments"), s(:hash, s(:lit, :force), s(:true))))
|
164
|
-
# }
|
165
102
|
def remember_table_nodes(node)
|
166
|
-
@table_name = node.arguments[
|
103
|
+
@table_name = node.arguments.all[0].to_s
|
167
104
|
@table_nodes[@table_name] = node
|
168
105
|
end
|
169
106
|
|
170
107
|
|
171
108
|
# remember foreign key columns
|
172
|
-
#
|
173
|
-
# if the message of node is :integer,
|
174
|
-
# then it is a foreign key, like
|
175
|
-
#
|
176
|
-
# s(:call, s(:lvar, :t), :integer, s(:arglist, s(:str, "post_id")))
|
177
|
-
#
|
178
|
-
# if the message of node is :string, with _type suffixed and there is a _id suffixed column,
|
179
|
-
# then they are polymorphic foreign key
|
180
|
-
#
|
181
|
-
# s(:call, s(:lvar, :t), :integer, s(:arglist, s(:str, "taggable_id")))
|
182
|
-
# s(:call, s(:lvar, :t), :string, s(:arglist, s(:str, "taggable_type")))
|
183
109
|
def remember_foreign_key_columns(node)
|
184
110
|
table_name = @table_name
|
185
|
-
foreign_key_column = node.arguments[
|
111
|
+
foreign_key_column = node.arguments.all[0].to_s
|
186
112
|
@foreign_keys[table_name] ||= []
|
187
113
|
if foreign_key_column =~ /(.*?)_id$/
|
188
114
|
if @foreign_keys[table_name].delete("#{$1}_type")
|