class RailsBestPractices::Reviews::AddModelVirtualAttributeReview
Make sure to add a model virual attribute to simplify model creation.
See the best practice details here rails-bestpractices.com/posts/2010/07/21/add-model-virtual-attribute/
Implementation:
Review
process:
check method define nodes in all controller files, if there are more than one [] method calls with the same receiver and arguments, but assigned to one model's different attribute. and after these method calls, there is a save method call for that model, then the model needs to add a virtual attribute.
Private Instance Methods
check an attribute assignment node, if there is a array reference node in the right value of assignment node, then remember this attribute assignment.
# File lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb, line 51 def assign(node) left_value = node.left_value right_value = node.right_value return unless left_value.sexp_type == :field && right_value.sexp_type == :call aref_node = right_value.grep_node(sexp_type: :aref) if aref_node assignments(left_value.receiver.to_s) << { message: left_value.message.to_s, arguments: aref_node.to_s } end end
get the assignments of receiver.
# File lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb, line 83 def assignments(receiver) @assignments[receiver] ||= [] end
check a call node with message “save” or “save!”, if there exists an attribute assignment for the receiver of this call node, and if the arguments of this attribute assignments has duplicated entries (different message and same arguments), then this node needs to add a virtual attribute.
# File lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb, line 66 def call_assignment(node) if ['save', 'save!'].include? node.message.to_s receiver = node.receiver.to_s add_error "add model virtual attribute (for #{receiver})" if params_dup?( assignments(receiver).collect { |h| h[:arguments] } ) end end
Get the duplicate entries from an Enumerable.
@return [Enumerable] the duplicate entries.
# File lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb, line 90 def dups(nodes) nodes.each_with_object({}) { |v, h| h[v] = h[v].to_i + 1 }.reject { |_k, v| v == 1 }.keys end
if the nodes are duplicated.
# File lib/rails_best_practices/reviews/add_model_virtual_attribute_review.rb, line 76 def params_dup?(nodes) return false if nodes.nil? !dups(nodes).empty? end