rails_best_practices 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/.rvmrc +1 -1
  2. data/.travis.yml +1 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +4 -2
  5. data/install_supported_rubies.sh +1 -1
  6. data/lib/rails_best_practices/core.rb +0 -1
  7. data/lib/rails_best_practices/core/check.rb +22 -3
  8. data/lib/rails_best_practices/core/checking_visitor.rb +24 -21
  9. data/lib/rails_best_practices/core/model_associations.rb +1 -1
  10. data/lib/rails_best_practices/core/routes.rb +3 -1
  11. data/lib/rails_best_practices/core_ext/sexp.rb +20 -13
  12. data/lib/rails_best_practices/prepares/controller_prepare.rb +8 -1
  13. data/lib/rails_best_practices/prepares/model_prepare.rb +1 -1
  14. data/lib/rails_best_practices/prepares/route_prepare.rb +16 -8
  15. data/lib/rails_best_practices/reviews.rb +1 -0
  16. data/lib/rails_best_practices/reviews/always_add_db_index_review.rb +1 -1
  17. data/lib/rails_best_practices/reviews/protect_mass_assignment_review.rb +45 -0
  18. data/lib/rails_best_practices/reviews/replace_instance_variable_with_local_variable_review.rb +9 -1
  19. data/lib/rails_best_practices/reviews/restrict_auto_generated_routes_review.rb +2 -2
  20. data/lib/rails_best_practices/reviews/use_before_filter_review.rb +1 -1
  21. data/lib/rails_best_practices/version.rb +1 -1
  22. data/rails_best_practices.gemspec +1 -1
  23. data/rails_best_practices.yml +1 -0
  24. data/rake_rubies.sh +2 -2
  25. data/spec/rails_best_practices/core_ext/sexp_spec.rb +15 -4
  26. data/spec/rails_best_practices/prepares/route_prepare_spec.rb +25 -2
  27. data/spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb +67 -0
  28. metadata +30 -28
  29. data/lib/rails_best_practices/core_ext/string.rb +0 -5
data/.rvmrc CHANGED
@@ -1,2 +1,2 @@
1
1
  rvm_gemset_create_on_use_flag=1
2
- rvm gemset use ruby-1.9.2-p290@rails_best_practices
2
+ rvm gemset use ruby-1.9.3-p125@rails_best_practices
data/.travis.yml CHANGED
@@ -1 +1 @@
1
- rvm: 1.9.2
1
+ rvm: 1.9.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_best_practices (1.8.0)
4
+ rails_best_practices (1.9.0)
5
5
  activesupport
6
6
  colored
7
7
  erubis
data/README.md CHANGED
@@ -19,6 +19,8 @@ following template engines:
19
19
  * haml
20
20
  * slim
21
21
 
22
+ rails_best_practices works well only in ruby 1.9.2 and ruby 1.9.3 so far.
23
+
22
24
  Usage
23
25
  -----
24
26
 
@@ -78,8 +80,6 @@ Install
78
80
 
79
81
  rails_best_practices gem is rewritten based on ripper instead of ruby_parser to support ruby 1.9 new syntax.
80
82
 
81
- Ruby 1.9
82
-
83
83
  gem install rails_best_practices
84
84
 
85
85
  or add in Gemfile
@@ -143,6 +143,7 @@ Now you can customize this configuration file, the default configuration is as f
143
143
  RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
144
144
  RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
145
145
  NotUseTimeAgoInWordsCheck: {}
146
+ ProtectMassAssignmentCheck: {}
146
147
 
147
148
  You can remove or comment one review to disable it, and you can change the options.
148
149
 
@@ -172,6 +173,7 @@ Model
172
173
  3. Use observer
173
174
  4. Use query attribute
174
175
  5. Remove unused methods in models
176
+ 6. Protect mass assignment
175
177
 
176
178
  Mailer
177
179
 
@@ -1,5 +1,5 @@
1
1
  #!/bin/bash
2
- rubies=( 1.8.7 1.9.2 ree )
2
+ rubies=( 1.9.2 1.9.3 )
3
3
  for x in ${rubies[*]}
4
4
  do
5
5
  rvm install $x
@@ -15,7 +15,6 @@ require 'rails_best_practices/core/controllers'
15
15
  require 'rails_best_practices/core/helpers'
16
16
  require 'rails_best_practices/core/routes'
17
17
 
18
- require 'rails_best_practices/core_ext/string'
19
18
  require 'rails_best_practices/core_ext/sexp'
20
19
  require 'rails_best_practices/core_ext/enumerable'
21
20
  require 'rails_best_practices/core_ext/erubis'
@@ -238,7 +238,7 @@ module RailsBestPractices
238
238
  module Callable
239
239
  def self.included(base)
240
240
  base.class_eval do
241
- interesting_nodes :call, :fcall, :var_ref, :command_call, :command, :alias, :bare_assoc_hash, :method_add_arg
241
+ interesting_nodes :call, :fcall, :var_ref, :vcall, :command_call, :command, :alias, :bare_assoc_hash, :method_add_arg
242
242
 
243
243
  # remembe the message of call node.
244
244
  add_callback "start_call" do |node|
@@ -255,6 +255,11 @@ module RailsBestPractices
255
255
  mark_used(node)
256
256
  end
257
257
 
258
+ # remembe name of vcall node.
259
+ add_callback "start_vcall" do |node|
260
+ mark_used(node)
261
+ end
262
+
258
263
  # skip start_command callback for these nodes
259
264
  def skip_command_callback_nodes
260
265
  []
@@ -346,7 +351,7 @@ module RailsBestPractices
346
351
  module InheritedResourcesable
347
352
  def self.included(base)
348
353
  base.class_eval do
349
- interesting_nodes :class, :var_ref
354
+ interesting_nodes :class, :var_ref, :vcall
350
355
  interesting_files CONTROLLER_FILES
351
356
 
352
357
  # check if the controller is inherit from InheritedResources::Base.
@@ -362,6 +367,13 @@ module RailsBestPractices
362
367
  @inherited_resources = true
363
368
  end
364
369
  end
370
+
371
+ # check if there is a DSL call inherit_resources.
372
+ add_callback "start_vcall" do |node|
373
+ if "inherit_resources" == node.to_s
374
+ @inherited_resources = true
375
+ end
376
+ end
365
377
  end
366
378
  end
367
379
  end
@@ -396,7 +408,7 @@ module RailsBestPractices
396
408
  module Accessable
397
409
  def self.included(base)
398
410
  base.class_eval do
399
- interesting_nodes :var_ref, :class, :module
411
+ interesting_nodes :var_ref, :vcall, :class, :module
400
412
 
401
413
  # remember the current access control for methods.
402
414
  add_callback "start_var_ref" do |node|
@@ -405,6 +417,13 @@ module RailsBestPractices
405
417
  end
406
418
  end
407
419
 
420
+ # remember the current access control for methods.
421
+ add_callback "start_vcall" do |node|
422
+ if %w(public protected private).include? node.to_s
423
+ @access_control = node.to_s
424
+ end
425
+ end
426
+
408
427
  # set access control to "public" by default.
409
428
  add_callback "start_class" do |node|
410
429
  @access_control = "public"
@@ -49,27 +49,30 @@ module RailsBestPractices
49
49
  # then run the reivew for that node.
50
50
  [:prepare, :review].each do |process|
51
51
  class_eval <<-EOS
52
- def #{process}(node) # def review(node)
53
- checks = @#{process}_checks[node.sexp_type] # checks = @review_checks[node.sexp_type]
54
- if checks # if checks
55
- checks.each { |check| # checks.each { |check|
56
- if check.parse_file?(node.file) # if check.parse_file?(node.file)
57
- check.node_start(node) # check.node_start(node)
58
- end # end
59
- } # }
60
- end # end
61
- node.children.each { |sexp| # node.children.each { |sexp|
62
- sexp.file = node.file # sexp.filename = node.file
63
- sexp.#{process}(self) # sexp.review(self)
64
- } # }
65
- if checks # if checks
66
- checks.each { |check| # checks.each { |check|
67
- if check.parse_file?(node.file) # if check.parse_file?(node.file)
68
- check.node_end(node) # check.node_end(node)
69
- end # end
70
- } # }
71
- end # end
72
- end # end
52
+ def #{process}(node) # def review(node)
53
+ checks = @#{process}_checks[node.sexp_type] # checks = @review_checks[node.sexp_type]
54
+ if checks # if checks
55
+ checks.each { |check| # checks.each { |check|
56
+ if check.parse_file?(node.file) # if check.parse_file?(node.file)
57
+ check.node_start(node) # check.node_start(node)
58
+ end # end
59
+ } # }
60
+ end # end
61
+ node.children.each { |sexp| # node.children.each { |sexp|
62
+ sexp.file = node.file # sexp.filename = node.file
63
+ sexp.#{process}(self) # sexp.review(self)
64
+ } # }
65
+ if checks # if checks
66
+ checks.each { |check| # checks.each { |check|
67
+ if check.parse_file?(node.file) # if check.parse_file?(node.file)
68
+ check.node_end(node) # check.node_end(node)
69
+ end # end
70
+ } # }
71
+ end # end
72
+ rescue Exception # rescue Exception
73
+ puts "find error in file: \#{node.file} line: \#{node.line}" # puts "find error in file: \#{node.file} line: \#{node.line}"
74
+ raise $! # raise $!
75
+ end # end
73
76
  EOS
74
77
  end
75
78
  end
@@ -48,7 +48,7 @@ module RailsBestPractices
48
48
  # @param [String] association_name
49
49
  # @return [String] association's class name
50
50
  def get_association_class_name(table_name, association_name)
51
- associations = @associations.select { |model, model_associations| model.table_name == table_name }.values.first and
51
+ associations = @associations.select { |model, model_associations| model.gsub("::", "").tableize == table_name }.values.first and
52
52
  association_meta = associations.select { |name, meta| name == association_name }.values.first and
53
53
  association_meta["class_name"]
54
54
  end
@@ -8,7 +8,9 @@ module RailsBestPractices
8
8
  # @param [String] controller name
9
9
  # @param [String] action name
10
10
  def add_route(namespaces, controller_name, action_name)
11
- self << Route.new(namespaces, controller_name, action_name)
11
+ if controller_name.present?
12
+ self << Route.new(namespaces, controller_name, action_name)
13
+ end
12
14
  end
13
15
  end
14
16
 
@@ -22,7 +22,7 @@ class Sexp
22
22
  # => 2
23
23
  def line
24
24
  if [:def, :defs, :command, :command_call, :call, :fcall, :method_add_arg, :method_add_block,
25
- :var_ref, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
25
+ :var_ref, :vcall, :const_ref, :const_path_ref, :class, :module, :if, :unless, :elsif, :binary,
26
26
  :alias, :symbol_literal, :symbol, :aref].include? sexp_type
27
27
  self[1].line
28
28
  elsif :array == sexp_type
@@ -56,17 +56,20 @@ class Sexp
56
56
  # :sexp_type => :call,
57
57
  # :subject => "Post",
58
58
  # :message => ["find", "new"]
59
+ # :to_s => "devise"
59
60
  #
60
- # the condition key is one of :sexp_type, :subject or :message,
61
+ # the condition key is one of :sexp_type, :subject, :message, :to_s,
61
62
  # the condition value can be Symbol, Array or Sexp.
62
63
  def grep_nodes(options)
63
64
  sexp_type = options[:sexp_type]
64
65
  subject = options[:subject]
65
66
  message = options[:message]
67
+ to_s = options[:to_s]
66
68
  self.recursive_children do |child|
67
69
  if (!sexp_type || (sexp_type.is_a?(Array) ? sexp_type.include?(child.sexp_type) : sexp_type == child.sexp_type)) &&
68
70
  (!subject || (subject.is_a?(Array) ? subject.include?(child.subject.to_s) : subject == child.subject.to_s)) &&
69
- (!message || (message.is_a?(Array) ? message.include?(child.message.to_s) : message == child.message.to_s))
71
+ (!message || (message.is_a?(Array) ? message.include?(child.message.to_s) : message == child.message.to_s)) &&
72
+ (!to_s || (to_s.is_a?(Array) ? to_s.include?(child.to_s) : to_s == child.to_s))
70
73
  yield child
71
74
  end
72
75
  end
@@ -82,7 +85,7 @@ class Sexp
82
85
  # :subject => s(:const, Post),
83
86
  # :message => [:find, :new]
84
87
  #
85
- # the condition key is one of :sexp_type, :subject, :message,
88
+ # the condition key is one of :sexp_type, :subject, :message, and to_s,
86
89
  # the condition value can be Symbol, Array or Sexp.
87
90
  def grep_node(options)
88
91
  result = RailsBestPractices::Core::Nil.new
@@ -295,13 +298,17 @@ class Sexp
295
298
  nodes = []
296
299
  case sexp_type
297
300
  when :args_add_block, :array
298
- node = self[1]
299
- while true
300
- if [:args_add, :args_add_star].include? node.sexp_type
301
- nodes.unshift node[2]
302
- node = node[1]
303
- elsif :args_new == node.sexp_type
304
- break
301
+ if self[1].sexp_type == :args_new
302
+ nodes << self[2]
303
+ else
304
+ node = self[1]
305
+ while true
306
+ if [:args_add, :args_add_star].include? node.sexp_type
307
+ nodes.unshift node[2]
308
+ node = node[1]
309
+ elsif :args_new == node.sexp_type
310
+ break
311
+ end
305
312
  end
306
313
  end
307
314
  end
@@ -754,7 +761,7 @@ class Sexp
754
761
  def to_s
755
762
  case sexp_type
756
763
  when :string_literal, :xstring_literal, :string_content, :const_ref, :symbol_literal, :symbol,
757
- :args_add_block, :var_ref, :var_field,
764
+ :args_add_block, :var_ref, :vcall, :var_field,
758
765
  :@ident, :@tstring_content, :@const, :@ivar, :@kw, :@gvar, :@cvar
759
766
  self[1].to_s
760
767
  when :string_add
@@ -788,7 +795,7 @@ class Sexp
788
795
 
789
796
  # check if the self node is a const.
790
797
  def const?
791
- :@const == self.sexp_type || (:var_ref == self.sexp_type && :@const == self[1].sexp_type)
798
+ :@const == self.sexp_type || ([:var_ref, :vcall].include?(self.sexp_type) && :@const == self[1].sexp_type)
792
799
  end
793
800
 
794
801
  # true
@@ -10,7 +10,7 @@ module RailsBestPractices
10
10
  include Core::Check::Accessable
11
11
  include Core::Check::Afterable
12
12
 
13
- interesting_nodes :class, :var_ref, :command, :def
13
+ interesting_nodes :class, :var_ref, :vcall, :command, :def
14
14
  interesting_files CONTROLLER_FILES
15
15
 
16
16
  DEFAULT_ACTIONS = %w(index show new create edit update destroy)
@@ -47,6 +47,13 @@ module RailsBestPractices
47
47
  end
48
48
  end
49
49
 
50
+ # check if there is a DSL call inherit_resources.
51
+ def start_vcall(node)
52
+ if @inherited_resources
53
+ @actions = DEFAULT_ACTIONS
54
+ end
55
+ end
56
+
50
57
  # restrict actions for inherited_resources
51
58
  def start_command(node)
52
59
  if "include" == node.message.to_s
@@ -9,7 +9,7 @@ module RailsBestPractices
9
9
  include Core::Check::Accessable
10
10
  include Core::Check::Afterable
11
11
 
12
- interesting_nodes :class, :def, :defs, :command, :var_ref, :alias
12
+ interesting_nodes :class, :def, :defs, :command, :alias
13
13
  interesting_files MODEL_FILES
14
14
 
15
15
  ASSOCIATION_METHODS = %w(belongs_to has_one has_many has_and_belongs_to_many embeds_many embeds_one embedded_in many one)
@@ -28,7 +28,11 @@ module RailsBestPractices
28
28
  first_argument = node.arguments.all.first
29
29
  second_argument = node.arguments.all[1]
30
30
  if @controller_names.last
31
- action_name = first_argument.to_s
31
+ if :bare_assoc_hash == first_argument.sexp_type
32
+ action_name = first_argument.hash_values.first.to_s
33
+ else
34
+ action_name = first_argument.to_s
35
+ end
32
36
  @routes.add_route(current_namespaces, current_controller_name, action_name)
33
37
  else
34
38
  if :bare_assoc_hash == first_argument.sexp_type
@@ -83,7 +87,7 @@ module RailsBestPractices
83
87
  else
84
88
  options = node.arguments.all.last
85
89
  if options.hash_value("controller").present?
86
- @controller_name = options.hash_value("controller").to_s
90
+ @controller_name = [:option, options.hash_value("controller").to_s]
87
91
  end
88
92
  action_name = options.hash_value("action").present? ? options.hash_value("action").to_s : "*"
89
93
  @routes.add_route(current_namespaces, current_controller_name, action_name)
@@ -100,11 +104,15 @@ module RailsBestPractices
100
104
  if node.arguments.all.last.hash_value("module").present?
101
105
  @namespaces << node.arguments.all.last.hash_value("module").to_s
102
106
  end
103
- @controller_name = nil
107
+ if node.arguments.all.last.hash_value("controller").present?
108
+ @controller_name = [:scope, node.arguments.all.last.hash_value("controller").to_s]
109
+ else
110
+ @controller_name = @controller_name.try(:first) == :scope ? @controller_name : nil
111
+ end
104
112
  when "with_options"
105
113
  argument = node.arguments.all.last
106
114
  if :bare_assoc_hash == argument.sexp_type && argument.hash_value("controller").present?
107
- @controller_name = argument.hash_value("controller").to_s
115
+ @controller_name = [:with_option, argument.hash_value("controller").to_s]
108
116
  end
109
117
  else
110
118
  # do nothing
@@ -127,7 +135,7 @@ module RailsBestPractices
127
135
 
128
136
  # remember current controller name, used for nested resources.
129
137
  def start_do_block(node)
130
- @controller_names << @controller_name
138
+ @controller_names << @controller_name.try(:last)
131
139
  end
132
140
 
133
141
  # remove current controller name, and use upper lever resource name.
@@ -140,13 +148,13 @@ module RailsBestPractices
140
148
  def add_#{route_name}_routes(node)
141
149
  resource_names = node.arguments.all.select { |argument| :symbol_literal == argument.sexp_type }
142
150
  resource_names.each do |resource_name|
143
- @controller_name = node.arguments.all.first.to_s
151
+ @controller_name = [:#{route_name}, node.arguments.all.first.to_s]
144
152
  options = node.arguments.all.last
145
153
  if options.hash_value("module").present?
146
154
  @namespaces << options.hash_value("module").to_s
147
155
  end
148
156
  if options.hash_value("controller").present?
149
- @controller_name = options.hash_value("controller").to_s
157
+ @controller_name = [:#{route_name}, options.hash_value("controller").to_s]
150
158
  end
151
159
  action_names = if options.hash_value("only").present?
152
160
  get_#{route_name}_actions(options.hash_value("only").to_object)
@@ -201,7 +209,7 @@ module RailsBestPractices
201
209
  end
202
210
 
203
211
  def current_controller_name
204
- @controller_names.last || @controller_name
212
+ @controller_names.last || @controller_name.try(:last)
205
213
  end
206
214
  end
207
215
  end
@@ -30,3 +30,4 @@ require 'rails_best_practices/reviews/remove_unused_methods_in_models_review'
30
30
  require 'rails_best_practices/reviews/remove_unused_methods_in_controllers_review'
31
31
  require 'rails_best_practices/reviews/remove_unused_methods_in_helpers_review'
32
32
  require 'rails_best_practices/reviews/not_use_time_ago_in_words_review'
33
+ require 'rails_best_practices/reviews/protect_mass_assignment_review'
@@ -130,7 +130,7 @@ module RailsBestPractices
130
130
  foreign_keys.delete_if do |key|
131
131
  if key =~ /_id$/
132
132
  class_name = Prepares.model_associations.get_association_class_name(table, key[0..-4])
133
- class_name ? !@table_nodes[class_name.table_name] : !@table_nodes[key[0..-4].pluralize]
133
+ class_name ? !@table_nodes[class_name.gsub("::", "").tableize] : !@table_nodes[key[0..-4].pluralize]
134
134
  end
135
135
  end
136
136
  end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ require 'rails_best_practices/reviews/review'
3
+
4
+ module RailsBestPractices
5
+ module Reviews
6
+ # Review model files to make sure to use attr_accessible or attr_protected to protect mass assignment.
7
+ #
8
+ # See the best practices details here http://rails-bestpractices.com/posts/148-protect-mass-assignment.
9
+ #
10
+ # Implmentation:
11
+ #
12
+ # Review process:
13
+ # check class node to see if there is a command with message attr_accessible or attr_protected.
14
+ class ProtectMassAssignmentReview < Review
15
+ interesting_nodes :class
16
+ interesting_files MODEL_FILES
17
+
18
+ def url
19
+ "http://rails-bestpractices.com/posts/148-protect-mass-assignment"
20
+ end
21
+
22
+ # check class node, grep all command nodes, if none of them is with message attr_accessible or attr_protected,
23
+ # then it should add attr_accessible or attr_protected to protect mass assignment.
24
+ def start_class(node)
25
+ if !rails_builtin?(node) && !devise?(node) && !authlogic?(node)
26
+ add_error "protect mass assignment"
27
+ end
28
+ end
29
+
30
+ private
31
+ def rails_builtin?(node)
32
+ node.grep_node(:sexp_type => :command, :message => %w(attr_accessible attr_protected)).present?
33
+ end
34
+
35
+ def devise?(node)
36
+ node.grep_node(:sexp_type => :command, :message => "devise").present?
37
+ end
38
+
39
+ def authlogic?(node)
40
+ node.grep_node(:sexp_type => :vcall, :to_s => "acts_as_authentic").present? ||
41
+ node.grep_node(:sexp_type => :fcall, :message => "acts_as_authentic").present?
42
+ end
43
+ end
44
+ end
45
+ end
@@ -13,7 +13,7 @@ module RailsBestPractices
13
13
  # check all instance variable in partial view files,
14
14
  # if exist, then they should be replaced with local variable
15
15
  class ReplaceInstanceVariableWithLocalVariableReview < Review
16
- interesting_nodes :var_ref
16
+ interesting_nodes :var_ref, :vcall
17
17
  interesting_files PARTIAL_VIEW_FILES
18
18
 
19
19
  def url
@@ -27,6 +27,14 @@ module RailsBestPractices
27
27
  add_error "replace instance variable with local variable"
28
28
  end
29
29
  end
30
+
31
+ # check ivar node in partial view file,
32
+ # it is an instance variable, and should be replaced with local variable.
33
+ def start_vcall(node)
34
+ if node.to_s.start_with?('@')
35
+ add_error "replace instance variable with local variable"
36
+ end
37
+ end
30
38
  end
31
39
  end
32
40
  end
@@ -86,10 +86,10 @@ module RailsBestPractices
86
86
  if hash_key_exist?(option_node,"controller")
87
87
  name = option_node.hash_value("controller").to_s
88
88
  else
89
- name = node.arguments.all.first.to_s.table_name
89
+ name = node.arguments.all.first.to_s.gsub("::", "").tableize
90
90
  end
91
91
  else
92
- name = node.arguments.all.first.to_s.table_name
92
+ name = node.arguments.all.first.to_s.gsub("::", "").tableize
93
93
  end
94
94
  namespaced_class_name(name)
95
95
  end
@@ -34,7 +34,7 @@ module RailsBestPractices
34
34
  @first_sentences = {}
35
35
 
36
36
  node.body.statements.each do |statement_node|
37
- break if :var_ref == statement_node.sexp_type && ["protected", "private"].include?(statement_node.to_s)
37
+ break if [:var_ref, :vcall].include?(statement_node.sexp_type) && ["protected", "private"].include?(statement_node.to_s)
38
38
  remember_first_sentence(statement_node) if :def == statement_node.sexp_type
39
39
  end
40
40
  @first_sentences.each do |first_sentence, def_nodes|
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module RailsBestPractices
3
- VERSION = "1.8.0"
3
+ VERSION = "1.9.0"
4
4
  end
@@ -42,7 +42,7 @@ Gem::Specification.new do |s|
42
42
 
43
43
  Please also try our online service
44
44
 
45
- https://railsbp.com
45
+ http://railsbp.com
46
46
 
47
47
  Enjoy!
48
48
 
@@ -31,3 +31,4 @@ RemoveUnusedMethodsInModelsCheck: { except_methods: [] }
31
31
  RemoveUnusedMethodsInControllersCheck: { except_methods: [] }
32
32
  RemoveUnusedMethodsInHelpersCheck: { except_methods: [] }
33
33
  NotUseTimeAgoInWordsCheck: { }
34
+ ProtectMassAssignmentCheck: { }
data/rake_rubies.sh CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/bin/bash
2
- rubies=( 1.9.2-p180 1.9.2-p290 1.9.3-p0 )
2
+ rubies=( 1.9.2-p290 1.9.3-p125 )
3
3
  gemset="rails_best_practices"
4
4
 
5
5
  for x in ${rubies[*]}
6
6
  do
7
7
  echo $x@$gemset
8
- rvm $x@$gemset do bundle exec rake spec:progress
8
+ rvm $x@$gemset do bundle exec rake spec
9
9
  done
@@ -48,13 +48,19 @@ describe Sexp do
48
48
  it "should get the call nodes with subject current_user" do
49
49
  nodes = []
50
50
  @node.grep_nodes(:sexp_type => :call, :subject => "current_user") { |node| nodes << node }
51
- nodes.should == [s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
51
+ nodes.should == [s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
52
52
  end
53
53
 
54
54
  it "should get the call nodes with different messages" do
55
55
  nodes = []
56
56
  @node.grep_nodes(:sexp_type => :call, :message => ["posts", "find"]) { |node| nodes << node }
57
- nodes.should == [s(:call, s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21))), :".", s(:@ident, "find", s(2, 27))), s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
57
+ nodes.should == [s(:call, s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21))), :".", s(:@ident, "find", s(2, 27))), s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))]
58
+ end
59
+
60
+ it "should get the vcall node with to_s" do
61
+ nodes = []
62
+ @node.grep_nodes(:sexp_type => :vcall, :to_s => "current_user") { |node| nodes << node }
63
+ nodes.should == [s(:vcall, s(:@ident, "current_user", s(2, 8)))]
58
64
  end
59
65
  end
60
66
 
@@ -70,7 +76,7 @@ describe Sexp do
70
76
 
71
77
  it "should get first node with empty argument" do
72
78
  node = @node.grep_node(:sexp_type => :call, :subject => "current_user")
73
- node.should == s(:call, s(:var_ref, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))
79
+ node.should == s(:call, s(:vcall, s(:@ident, "current_user", s(2, 8))), :".", s(:@ident, "posts", s(2, 21)))
74
80
  end
75
81
  end
76
82
 
@@ -221,7 +227,7 @@ describe Sexp do
221
227
  node.arguments.sexp_type.should == :args_add_block
222
228
  end
223
229
 
224
- it "should get the arguments of method_add_args" do
230
+ it "should get the arguments of method_add_arg" do
225
231
  node = parse_content("User.find(:all)").grep_node(:sexp_type => :method_add_arg)
226
232
  node.arguments.sexp_type.should == :args_add_block
227
233
  end
@@ -245,6 +251,11 @@ describe Sexp do
245
251
  node.all.map(&:to_s).should == ["hello", "world"]
246
252
  end
247
253
 
254
+ it "should get all arguments with &:" do
255
+ node = parse_content("user.posts.map(&:title)").grep_node(:sexp_type => :args_add_block)
256
+ node.all.map(&:to_s).should == ["title"]
257
+ end
258
+
248
259
  it "no error for args_add_star" do
249
260
  node = parse_content("send(:\"\#{route}_url\", *args)").grep_node(:sexp_type => :args_add_block)
250
261
  lambda { node.all }.should_not raise_error
@@ -505,11 +505,23 @@ describe RailsBestPractices::Prepares::RoutePrepare do
505
505
  scope "/admin" do
506
506
  resources :comments, :only => [:index]
507
507
  end
508
+ scope "/:username", controller: :users do
509
+ get '/' => :show
510
+ scope 'topic' do
511
+ get 'preview', :as => 'preview_user', :action => 'preview'
512
+ end
513
+ end
508
514
  end
509
515
  EOF
510
516
  runner.prepare('config/routes.rb', content)
511
517
  routes = RailsBestPractices::Prepares.routes
512
- routes.map(&:to_s).should == ["Admin::PostsController#index", "Admin::DiscussionsController#index", "CommentsController#index"]
518
+ routes.map(&:to_s).should == [
519
+ "Admin::PostsController#index",
520
+ "Admin::DiscussionsController#index",
521
+ "CommentsController#index",
522
+ "UsersController#show",
523
+ "UsersController#preview"
524
+ ]
513
525
  end
514
526
  end
515
527
 
@@ -531,7 +543,7 @@ describe RailsBestPractices::Prepares::RoutePrepare do
531
543
 
532
544
  it "should add routes for another get/post" do
533
545
  content =<<-EOF
534
- RailsBestPracticesCom::Application.routes.draw do
546
+ RailsBestPracticesCom::Application.routes.draw
535
547
  get "/login", to: 'sessions#new', as: :login
536
548
  end
537
549
  EOF
@@ -622,5 +634,16 @@ describe RailsBestPractices::Prepares::RoutePrepare do
622
634
  routes = RailsBestPractices::Prepares.routes
623
635
  routes.last.to_s.should == "SprintsController#stop"
624
636
  end
637
+
638
+ it "should not parse wrong route" do
639
+ content =<<-EOF
640
+ RailsBestPracticesCom::Application.routes.draw do
641
+ match ':controller/:action' => '#index', :as => :auto_complete
642
+ end
643
+ EOF
644
+ runner.prepare('config/routes.rb', content)
645
+ routes = RailsBestPractices::Prepares.routes
646
+ routes.size.should == 0
647
+ end
625
648
  end
626
649
  end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsBestPractices::Reviews::ProtectMassAssignmentReview do
4
+ let(:runner) { RailsBestPractices::Core::Runner.new(:reviews => RailsBestPractices::Reviews::ProtectMassAssignmentReview.new) }
5
+
6
+ it "should protect mass assignment" do
7
+ content =<<-EOF
8
+ class User < ActiveRecord::Base
9
+ end
10
+ EOF
11
+ runner.review('app/models/user.rb', content)
12
+ runner.should have(1).errors
13
+ runner.errors[0].to_s.should == "app/models/user.rb:1 - protect mass assignment"
14
+ end
15
+
16
+ it "should not protect mass assignment with attr_accessible" do
17
+ content =<<-EOF
18
+ class User < ActiveRecord::Base
19
+ attr_accessible :email, :password, :password_confirmation
20
+ end
21
+ EOF
22
+ runner.review('app/models/user.rb', content)
23
+ runner.should have(0).errors
24
+ end
25
+
26
+ it "should not protect mass assignment with attr_protected" do
27
+ content =<<-EOF
28
+ class User < ActiveRecord::Base
29
+ attr_protected :role
30
+ end
31
+ EOF
32
+ runner.review('app/models/user.rb', content)
33
+ runner.should have(0).errors
34
+ end
35
+
36
+ it "should not protect mass assignment if using devise" do
37
+ content =<<-EOF
38
+ class User < ActiveRecord::Base
39
+ devise :database_authenticatable, :registerable, :confirmable, :recoverable, :stretches => 20
40
+ end
41
+ EOF
42
+ runner.review('app/models/user.rb', content)
43
+ runner.should have(0).errors
44
+ end
45
+
46
+ it "should not protect mass assignment if using authlogic with configuration" do
47
+ content =<<-EOF
48
+ class User < ActiveRecord::Base
49
+ acts_as_authentic do |c|
50
+ c.my_config_option = my_value
51
+ end
52
+ end
53
+ EOF
54
+ runner.review('app/models/user.rb', content)
55
+ runner.should have(0).errors
56
+ end
57
+
58
+ it "should not protect mass assignment if using authlogic without configuration" do
59
+ content =<<-EOF
60
+ class User < ActiveRecord::Base
61
+ acts_as_authentic
62
+ end
63
+ EOF
64
+ runner.review('app/models/user.rb', content)
65
+ runner.should have(0).errors
66
+ end
67
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_best_practices
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-24 00:00:00.000000000Z
12
+ date: 2012-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sexp_processor
16
- requirement: &70270463469100 !ruby/object:Gem::Requirement
16
+ requirement: &70152469216300 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70270463469100
24
+ version_requirements: *70152469216300
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: progressbar
27
- requirement: &70270463467440 !ruby/object:Gem::Requirement
27
+ requirement: &70152469214420 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70270463467440
35
+ version_requirements: *70152469214420
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: colored
38
- requirement: &70270463456860 !ruby/object:Gem::Requirement
38
+ requirement: &70152469213480 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70270463456860
46
+ version_requirements: *70152469213480
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: erubis
49
- requirement: &70270463455020 !ruby/object:Gem::Requirement
49
+ requirement: &70152469212320 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70270463455020
57
+ version_requirements: *70152469212320
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: i18n
60
- requirement: &70270463453880 !ruby/object:Gem::Requirement
60
+ requirement: &70152469211160 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70270463453880
68
+ version_requirements: *70152469211160
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activesupport
71
- requirement: &70270463452620 !ruby/object:Gem::Requirement
71
+ requirement: &70152469209960 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *70270463452620
79
+ version_requirements: *70152469209960
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rake
82
- requirement: &70270463451560 !ruby/object:Gem::Requirement
82
+ requirement: &70152469209140 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70270463451560
90
+ version_requirements: *70152469209140
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rspec
93
- requirement: &70270463450820 !ruby/object:Gem::Requirement
93
+ requirement: &70152469208480 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70270463450820
101
+ version_requirements: *70152469208480
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: haml
104
- requirement: &70270463450120 !ruby/object:Gem::Requirement
104
+ requirement: &70152469207680 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70270463450120
112
+ version_requirements: *70152469207680
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: slim
115
- requirement: &70270463444400 !ruby/object:Gem::Requirement
115
+ requirement: &70152469206760 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70270463444400
123
+ version_requirements: *70152469206760
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: bundler
126
- requirement: &70270463443380 !ruby/object:Gem::Requirement
126
+ requirement: &70152469205560 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *70270463443380
134
+ version_requirements: *70152469205560
135
135
  description: a code metric tool for rails codes, written in Ruby.
136
136
  email:
137
137
  - flyerhzm@gmail.com
@@ -179,7 +179,6 @@ files:
179
179
  - lib/rails_best_practices/core_ext/enumerable.rb
180
180
  - lib/rails_best_practices/core_ext/erubis.rb
181
181
  - lib/rails_best_practices/core_ext/sexp.rb
182
- - lib/rails_best_practices/core_ext/string.rb
183
182
  - lib/rails_best_practices/lexicals.rb
184
183
  - lib/rails_best_practices/lexicals/remove_tab_check.rb
185
184
  - lib/rails_best_practices/lexicals/remove_trailing_whitespace_check.rb
@@ -206,6 +205,7 @@ files:
206
205
  - lib/rails_best_practices/reviews/not_use_default_route_review.rb
207
206
  - lib/rails_best_practices/reviews/not_use_time_ago_in_words_review.rb
208
207
  - lib/rails_best_practices/reviews/overuse_route_customizations_review.rb
208
+ - lib/rails_best_practices/reviews/protect_mass_assignment_review.rb
209
209
  - lib/rails_best_practices/reviews/remove_empty_helpers_review.rb
210
210
  - lib/rails_best_practices/reviews/remove_unused_methods_in_controllers_review.rb
211
211
  - lib/rails_best_practices/reviews/remove_unused_methods_in_helpers_review.rb
@@ -270,6 +270,7 @@ files:
270
270
  - spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
271
271
  - spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
272
272
  - spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
273
+ - spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb
273
274
  - spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
274
275
  - spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
275
276
  - spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb
@@ -292,7 +293,7 @@ licenses: []
292
293
  post_install_message: ! "********************************************************************************\n\n
293
294
  \ rails_best_practices is a code metric tool to check the quality of rails codes.\n\n
294
295
  \ I highly recommend you browse the Rails Best Practices website first.\n\n http://rails-bestpractices.com\n\n
295
- \ Please also try our online service\n\n https://railsbp.com\n\n Enjoy!\n\n
296
+ \ Please also try our online service\n\n http://railsbp.com\n\n Enjoy!\n\n
296
297
  \ Richard Huang (flyerhzm@gmail.com)\n\n********************************************************************************\n"
297
298
  rdoc_options: []
298
299
  require_paths:
@@ -306,7 +307,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
306
307
  version: '0'
307
308
  segments:
308
309
  - 0
309
- hash: 920336894600409116
310
+ hash: -964066537248826324
310
311
  required_rubygems_version: !ruby/object:Gem::Requirement
311
312
  none: false
312
313
  requirements:
@@ -315,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
316
  version: 1.3.6
316
317
  requirements: []
317
318
  rubyforge_project:
318
- rubygems_version: 1.8.15
319
+ rubygems_version: 1.8.17
319
320
  signing_key:
320
321
  specification_version: 3
321
322
  summary: a code metric tool for rails codes.
@@ -363,6 +364,7 @@ test_files:
363
364
  - spec/rails_best_practices/reviews/not_use_default_route_review_spec.rb
364
365
  - spec/rails_best_practices/reviews/not_use_times_ago_in_words_review_spec.rb
365
366
  - spec/rails_best_practices/reviews/overuse_route_customizations_review_spec.rb
367
+ - spec/rails_best_practices/reviews/protect_mass_assignment_review_spec.rb
366
368
  - spec/rails_best_practices/reviews/remove_empty_helpers_review_spec.rb
367
369
  - spec/rails_best_practices/reviews/remove_unused_methods_in_controllers_review_spec.rb
368
370
  - spec/rails_best_practices/reviews/remove_unused_methods_in_helpers_review_spec.rb
@@ -1,5 +0,0 @@
1
- class String
2
- def table_name
3
- self.gsub("::", "").tableize
4
- end
5
- end