0

tl;dr: include MyModuleRailsMyModuleコンソールで実行すると の関数がスコープに含まれますが、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>'

世界で何が起こっているのですか?コンソールが見つけた関数をサーバーが見つけられないのはなぜですか?

4

1 に答える 1

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クラスメソッドである必要があります。モジュールのフックを使用してこれを行うことができます。selfmincluded

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

これで、目的のコンテキストで呼び出すことができるクラス メソッドが作成されますUservalidates_zip

于 2013-05-03T04:07:25.637 に答える