【问题标题】:Rails console includes differently than modelRails 控制台包含的内容与模型不同
【发布时间】:2013-05-03 03:36:13
【问题描述】:

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

当我尝试启动服务器(瘦)时,它会出错:

/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>'

世界上到底发生了什么?为什么服务器找不到控制台找到的函数?

【问题讨论】:

    标签: ruby-on-rails include


    【解决方案1】:

    考虑一下:

    module M
      def m
      end
    end
    
    class C
      include M
    end
    

    鉴于此,您可以毫无怨言地说C.new.m,但不能C.m。那么这里发生了什么?当你说 include M 时,M 中的方法将作为 instance 方法添加到 C 但如果你想说:

    class C
      include M
      m
    end
    

    那么 m 必须是一个 class 方法,因为当您调用 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 类方法,您可以在所需的上下文中调用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2022-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-07
      • 2013-06-11
      相关资源
      最近更新 更多