tl; dr:include MyModule
在rails控制台中运行时将MyModule
的函数带入范围,但在rails模型中则不行。我不理解,并希望能够在我的模型中访问这些功能。
我有这个文件lib/zip_validator.rb
,我想用它来验证我的User
模型的用户输入。
module ActiveModel::Validations::HelperMethods
def validates_zip(*attr_names)
validates_with ZipValidator, _merge_attributes( attr_names )
end
end
class ZipValidator < ActiveModel::EachValidator
def validate_each( record, attr_name, value )
unless is_legitimate_zipcode( self.zip )
record.errors.add( attr_name, :zip, options.merge( value: value ))
end
end
end
在rails控制台中,我可以
irb(main):005:0> include ActiveModel::Validations::HelperMethods
=> Object
irb(main):006:0> validates_zip
NoMethodError: undefined method `validates_with' for main:Object
from /home/bistenes/Programming/myapp/lib/zip_validator.rb:3:in `validates_zip'
from (irb):6
from /usr/lib64/ruby/gems/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /usr/lib64/ruby/gems/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /usr/lib64/ruby/gems/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
看!显然它找到了validates_zip
,因为它抱怨该方法中的电话。当我真正尝试从将要使用它的模型中调用它时,这个投诉可能就会消失,app/models/user.rb
:
class User < ActiveRecord::Base
include ActiveModel::Validations::HelperMethods
attr_accessible :first_name, :last_name, :zip, :email, :password,
:password_confirmation, :remember_me, :confirmed_at
validates_presence_of :first_name, :last_name, :zip
validates_zip :zip
当我尝试启动服务器(Thin)时,错误输出:
/usr/lib64/ruby/gems/1.9.1/gems/activerecord-3.2.13/lib/active_record/dynamic_matchers.rb:55:in `method_missing': undefined method `validates_zip' for #<Class:0x00000003e03f28> (NoMethodError)
from /home/bistenes/Programming/myapp/app/models/user.rb:38:in `<class:User>'
世界上发生了什么?为什么服务器找不到控制台找到的功能?
答案 0 :(得分:0)
考虑一下:
module M
def m
end
end
class C
include M
end
鉴于此,您可以在没有投诉的情况下说C.new.m
,但不能C.m
。那么这里发生了什么?当您说include M
时,M
中的方法将作为实例方法添加到C
,但如果您想说:
class C
include M
m
end
然后m
必须是类方法,因为self
,当您在此处调用m
时,这是类本身。您可以使用模块中的included
挂钩来执行此操作:
module M
def self.included(base)
base.class_exec do
def m
end
end
end
end
class C
include M
m # This works now
end
在你的情况下,你会有这样的事情:
module ActiveModel::Validations::HelperMethods
def self.included(base)
base.class_exec do
def self.validates_zip(*attr_names)
validates_with ZipValidator, _merge_attributes( attr_names )
end
end
end
end
现在,您的User
将拥有一个validates_zip
类方法,您可以在所需的上下文中调用该方法。