Ruby, Rails and aliasing - stack too deep problem
My problem is with calling old aliased method in Test environment. Probably only with Factory Girl
app/models/user.rb
class User < ActiveRecord::Base
...
include Authentication
include Authentication::ByPassword
...
attr_accessor :skip_password_validations
alias old_password_required? password_required?
# alias_method :old_password_required?, :password_required?
def password_required?
return false if !!skip_password_validations
old_password_required?
end
# def password_required_with_skip_validations?
# return false if !!skip_password_validations
# password_required_without_skip_validations?
# end
# alias_method_chain :password_required?, :skip_validations
end
vendor/plugins/../by_password.rb
module Authentication
module ByPassword
# Stuff directives into including module
def self.included(recipient)
recipient.class_eval do
include ModelInstanceMethods
attr_accessor :password
validates_presence_of :password, :if => :password_required?
end
开发者_JAVA百科 end # #included directives
module ModelInstanceMethods
def password_required?
crypted_password.blank? || !password.blank?
end
end # instance methods
end
end
spec/models/user_spec.rb
describe User do
it 'test' do
@user = Factory(:user)
@user.should be_valid
end
end
spec/factories/user_factories.rb
FactoryGirl.define do
factory :user do |u|
u.sequence(:email) { |n| "login#{n}@example.com" }
u.password 'qwertz123'
u.password_confirmation 'qwertz123'
end
end
Result is
1) User test
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
# /Users/schovi/.rvm/gems/ruby-1.9.2-p180/gems/activerecord-3.1.0.rc4/lib/active_record/connection_adapters/abstract/database_statements.rb:197
When i debug it with debugger gem, I found that method old_password_required?
point to the new method password_required?
in user.rb
and not in vendor/plugins/../by_password.rb
Get same result with alias, alias_method or alias_method_chain
Any idea?
My opinion is: Using alias
in Ruby is often a pain in the ass. So how about moving your password_required?
into it's own Module and the calling super
inside it, to call password_required?
from Authentication::ByPassword::ModelInstanceMethods
like so:
class User < ActiveRecord::Base
module PasswordRequired
def password_required?
return false if !!skip_password_validations
super # Is going to call Authentication's password_required?
end
end
include Authentication
include Authentication::ByPassword
include PasswordRequired
...
end
精彩评论