SystemStackError: stack level too deep

valid_for_[a group]

class User

include Validatable



attr_accessor :first_name, :last_name, :ssn

validates_presence_of :first_name, :last_name, :ssn, :groups => :account_creation

validates_presence_of :ssn, :groups => :persistence

end

irb(main):010:0> user = User.new

=> #<User:0x696900>

irb(main):011:0> user.ssn = 111223333

=> 111223333

irb(main):012:0> user.valid_for_persistence?

=> true

irb(main):013:0> user.valid_for_account_creation?

=> false

irb(main):014:0> user.first_name = 'Shane'

=> "Shane"

irb(main):015:0> user.last_name = 'Harvie'

=> "Harvie"

irb(main):016:0> user.valid_for_persistence?

=> true

irb(main):017:0> user.valid_for_account_creation?

=> true



something

Delegate Responsibility

irb(main):010:0> user = User.new

=> #<User:0x696900>

irb(main):011:0> user.ssn = 111223333

=> 111223333

irb(main):012:0> user.valid_for.persistence?

=> true

irb(main):013:0> user.valid_for.account_creation?

=> false

Metaprogramming

def create_valid_method_for_groups(groups) #:nodoc:

groups.each do |group|

self.class_eval do

define_method "valid_for_#{group}?".to_sym do

valid_for_group?(group)

end

end

end

end

I love the value that method_missing provides; unfortunately, sometimes I get into trouble when I abuse the power Matz has bestowed upon me. If you've done much work with method_missing the following error message probably isn't foreign to you.It's a painful message to see, as it's always problematic to debug. Given the inherent difficultly of debugging method_missing calls I thought it might be valuable to offer a few alternatives.As an example I'll use themethods that Validatable exposes. The Validatable validations allow you to put your validations into groups.Given the above User class you can expect the following behavior.As you can see the User instance exposes the valid_for_account_creation? and the valid_for_persistence? methods. Of course, we want the valid_for_[a group] methods to change based on the groups defined in each class. Additionally, we only want valid_for_something? to be defined on a class if that class contains any validations in thegroup. This looks like a classic situation for using method_missing; however, I chose one of the following other solutions.The basic idea behind this solution alternative is to move the method_missing logic into a class whose sole responsibility is the method_missing logic. For example, had I chosen this solution for Validatable I would have made the valid methods work like the following example.Given the above syntax I could have created a ValidFor class that encapsulated the logic for dynamically executing a subset of validations. A few cons for this solution are the obvious violation of the Law of Demeter and the fact that the stack overflow can still exist in the delegate class. However, I like to use this solution when the methods that are necessary are truly dynamic and cannot be easily predicted (i.e. the find_by_* methods that ActiveRecord::Base exposes). Additionally, the added class removes variables when trying to figure out where the logic went wrong.I chose this solution because I was able to easily identify which methods were necessary and define then at interpretation time. In fact the implementation for defining the valid methods is quite simple.Given the above code a class will define a new valid_for_[a group] method for each group given to any of it's validations. By explicitly defining each method I get much more manageable error messages when things do go wrong.