# encoding: utf-8 module RailsBestPractices module Reviews # Review a controller to make sure to use scope access instead of manually checking current_user and redirect. # # See the best practice details here http://rails-bestpractices.com/posts/2010/07/20/use-scope-access/ # # Implementation: # # Review process: # check all if nodes to see # # if they are compared with current_user or current_user.id, # and there is redirect_to method call in if block body, # then it should be replaced by using scope access. class UseScopeAccessReview < Review interesting_nodes :if, :unless, :elsif, :ifop, :if_mod, :unless_mod interesting_files CONTROLLER_FILES url "http://rails-bestpractices.com/posts/2010/07/20/use-scope-access/" # check if node. # # if it is a method call compared with current_user or current_user.id, # and there is a redirect_to method call in the block body, # then it should be replaced by using scope access. add_callback :start_if, :start_unless, :start_elsif, :start_ifop, :start_if_mod, :start_unless_mod do |node| add_error "use scope access" if current_user_redirect?(node) end private # check a if node to see # # if the conditional statement is compared with current_user or current_user.id, # and there is a redirect_to method call in the block body, # then it should be replaced by using scope access. def current_user_redirect?(node) all_conditions = if node.conditional_statement == node.conditional_statement.all_conditions [node.conditional_statement] else node.conditional_statement.all_conditions end results = all_conditions.map do |condition_node| ["==", "!="].include?(condition_node.message.to_s) && (current_user?(condition_node.argument) || current_user?(condition_node.receiver)) end results.any? { |result| result == true } && node.body.grep_node(message: "redirect_to") end # check a call node to see if it uses current_user, or current_user.id. def current_user?(node) "current_user" == node.to_s || ("current_user" == node.receiver.to_s && "id" == node.message.to_s) end end end end