Class: RailsBestPractices::Reviews::AlwaysAddDbIndexReview
- Inherits:
-
Review
- Object
- Core::Check
- Review
- RailsBestPractices::Reviews::AlwaysAddDbIndexReview
- Defined in:
- lib/rails_best_practices/reviews/always_add_db_index_review.rb
Overview
Review db/schema.rb file to make sure every reference key has a database index.
See the best practice details here rails-bestpractices.com/posts/21-always-add-db-index
Implementation:
Review process:
only check the call nodes and at the end of iter node in db/schema file,
if the subject of call node is :create_table, then remember the table names
if the subject of call node is :integer, then remember it as foreign key
if the sujbect of 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
if the subject of call node is :add_index, then remember the index columns
after all of these, at the end of iter node
ActiveRecord::Schema.define(:version => 20101201111111) do
......
end
if there are any foreign keys not existed in index columns,
then the foreign keys should add db index.
Constant Summary
Constants inherited from Core::Check
Core::Check::CONTROLLER_FILES, Core::Check::HELPER_FILES, Core::Check::MAILER_FILES, Core::Check::MIGRATION_FILES, Core::Check::MODEL_FILES, Core::Check::NODE_TYPES, Core::Check::PARTIAL_VIEW_FILES, Core::Check::ROUTE_FILE, Core::Check::SCHEMA_FILE, Core::Check::VIEW_FILES
Instance Attribute Summary
Attributes inherited from Core::Check
Instance Method Summary collapse
-
#end_iter(node) ⇒ Object
check at the end of iter node, like.
-
#initialize ⇒ AlwaysAddDbIndexReview
constructor
A new instance of AlwaysAddDbIndexReview.
- #interesting_files ⇒ Object
- #interesting_nodes ⇒ Object
-
#start_call(node) ⇒ Object
check call node.
- #url ⇒ Object
Methods inherited from Review
#equal?, #model_associations, #model_attributes, #models, #remember_variable_use_count, #reset_variable_use_count, #variable, #variable_use_count
Methods inherited from Core::Check
#add_error, #method_missing, #node_end, #node_start
Constructor Details
#initialize ⇒ AlwaysAddDbIndexReview
Returns a new instance of AlwaysAddDbIndexReview.
39 40 41 42 43 44 |
# File 'lib/rails_best_practices/reviews/always_add_db_index_review.rb', line 39 def initialize super @index_columns = {} @foreign_keys = {} @table_nodes = {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class RailsBestPractices::Core::Check
Instance Method Details
#end_iter(node) ⇒ Object
check at the end of iter node, like
s(:iter,
s(:call,
s(:colon2, s(:const, :ActiveRecord), :Schema),
:define,
s(:arglist, s(:hash, s(:lit, :version), s(:lit, 20100603080629)))
),
nil,
s(:iter,
s(:call, nil, :create_table,
s(:arglist, s(:str, "comments"), s(:hash, s(:lit, :force), s(:true)))
),
s(:lasgn, :t),
s(:block,
s(:call, s(:lvar, :t), :string, s(:arglist, s(:str, "content")))
)
)
)
if the subject of iter node is with subject ActiveRecord::Schema, it means we have completed the foreign keys and index columns parsing, then we compare foreign keys and index columns.
if there are any foreign keys not existed in index columns, then we should add db index for that foreign keys.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/rails_best_practices/reviews/always_add_db_index_review.rb', line 113 def end_iter(node) first_node = node.subject if :call == first_node.node_type && s(:colon2, s(:const, :ActiveRecord), :Schema) == first_node.subject remove_only_type_foreign_keys @foreign_keys.each do |table, foreign_key| table_node = @table_nodes[table] foreign_key.each do |column| if indexed?(table, column) add_error "always add db index (#{table} => [#{Array(column).join(', ')}])", table_node.file, table_node.line end end end end end |
#interesting_files ⇒ Object
35 36 37 |
# File 'lib/rails_best_practices/reviews/always_add_db_index_review.rb', line 35 def interesting_files SCHEMA_FILE end |
#interesting_nodes ⇒ Object
31 32 33 |
# File 'lib/rails_best_practices/reviews/always_add_db_index_review.rb', line 31 def interesting_nodes [:call, :iter] end |
#start_call(node) ⇒ Object
check call node.
if the message of call node is :create_table, then remember the table name (@table_nodes) like
{
"comments" =>
s(:call, nil, :create_table, s(:arglist, s(:str, "comments"), s(:hash, s(:lit, :force), s(:true))))
}
if the message of call node is :integer, then remember it as a foreign key of last create table name.
if the message of call node is :type and the name of argument is _type suffixed, then remember it with _id suffixed column as polymorphic foreign key.
the remember foreign keys (@foreign_keys) like
{
"taggings" =>
["tag_id", ["taggable_id", "taggable_type"]]
}
if the message of call node is :add_index, then remember it as index columns (@index_columns) like
{
"comments" =>
["post_id", "user_id"]
}
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rails_best_practices/reviews/always_add_db_index_review.rb', line 75 def start_call(node) case node. when :create_table remember_table_nodes(node) when :integer, :string remember_foreign_key_columns(node) when :add_index remember_index_columns(node) else end end |
#url ⇒ Object
27 28 29 |
# File 'lib/rails_best_practices/reviews/always_add_db_index_review.rb', line 27 def url "http://rails-bestpractices.com/posts/21-always-add-db-index" end |