简体   繁体   English

来自类中Private方法的NoMethodError(未定义方法)

[英]NoMethodError (undefined method) from Private method in class

Why can't I use a private method from within my class? 为什么我不能在课堂上使用私有方法? How do I fix my code to prevent the error? 如何修复我的代码以防止错误?

module CarRegistration
  class Basics < Base

    fields_of_model(:car).each do |attr|
      delegate attr.to_sym, "#{attr}=".to_sym, to: :car
    end

    private

    car_structure = #array of hashes

    def fields_of_model(model)
      car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
    end
end

error 错误

NoMethodError (undefined method `fields_of_model' for CarRegistration::Basics:Class): NoMethodError(CarRegistration :: Basics:Class的未定义方法`fields_of_model'):

I think you have a number of problems going on here. 我认为您在这里遇到了许多问题。

First, you've defined fields_of_model as an instance method, here: 首先,您已经将fields_of_model定义为实例方法,在这里:

def fields_of_model(model)
  car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
end

but you're trying to call it from the class, here: 但您正在尝试从班级中调用它:

fields_of_model(:car).each do |attr|
  delegate attr.to_sym, "#{attr}=".to_sym, to: :car
end

So, you'll want to make fields_of_model a class method, and define it before you call it. 因此,您需要将fields_of_model一个类方法,并在调用它之前对其进行定义。 Something like: 就像是:

module CarRegistration
  class Basics < Base

    private

    car_structure = #array of hashes

    class << self

      def fields_of_model(model)
        car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
      end

    end

    fields_of_model(:car).each do |attr|
      delegate attr.to_sym, "#{attr}=".to_sym, to: :car
    end

end

You'll also have problems with that car_structure variable, I think, because it'll be out of scope for the class method. 我认为,您还会遇到那个car_structure变量问题,因为它将超出类方法的范围。 So, I think you need to make a class-level instance variable. 因此,我认为您需要制作一个类级实例变量。 So, give this a try: 因此,尝试一下:

module CarRegistration
  class Basics < Base

    @car_structure = #array of hashes

    class << self

      def fields_of_model(model)
        @car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
      end

      private :fields_of_model

    end

    fields_of_model(:car).each do |attr|
      delegate attr.to_sym, "#{attr}=".to_sym, to: :car
    end

end

Note that I made the class method, :fields_of_models private using private :fields_of_model . 请注意,我使用private :fields_of_model将类方法:fields_of_models私有。

To demonstrate the whole thing, I ginned up this RSpec test: 为了演示整个过程,我进行了RSpec测试:

require 'rails_helper'

class Car

  attr_accessor *%w(
    color
    make
    year
  ).freeze

end

module CarRegistration
  class Basic

    @car_structure = [
      {model: :car, name: :color},
      {model: :car, name: :make},
      {model: :car, name: :year}
    ]

    class << self

      def fields_of_model(model)
        @car_structure.select {|record| record[:model] == model}.map{|record| record[:name]}
      end

      private :fields_of_model

    end

      fields_of_model(:car).each do |attr|
        delegate attr.to_sym, "#{attr}=".to_sym, to: :car
      end

      def car
        @car ||= Car.new 
      end

  end
end

RSpec.describe CarRegistration::Basic do
    it "has :fields_of_model as a private class method" do 
      expect(CarRegistration::Basic.public_methods).not_to include(:fields_of_model)
      expect(CarRegistration::Basic.private_methods).to include(:fields_of_model)
    end
    it "responds to :color and :color=" do
      expect(car_registration).to respond_to(:color)
      expect(car_registration).to respond_to(:color=)
    end
    it "sets and gets attributes on car" do
      expect(car_registration.color).to be_nil
      expect(car_registration.car.color).to be_nil
      car_registration.color = :red
      expect(car_registration.car.color).to eq(:red)
      expect(car_registration.color).to eq(:red)
      expect(car_registration.instance_variable_get(:@color)).to be_nil 
    end
end

def car_registration
  @car_registration ||= described_class.new
end

Which, when run, yields: 运行时产生以下结果:

CarRegistration::Basic
  has :fields_of_model as a private class method
  responds to :color and :color=
  sets and gets attributes on car

Finished in 0.733 seconds (files took 27.84 seconds to load)
3 examples, 0 failures

BTW, having this code in your class outside of a def - end is just fine and not the root of your problem. 顺便说一句,有外部你们班这个代码def - end是蛮好的,而不是你的问题的根源。 In fact, it's quite normal. 实际上,这很正常。

Also, I will note that Jörg W Mittag wishes to say: 另外,我会注意到JörgW Mittag希望说:

I am one of those Ruby Purists who likes to point out that there is no such thing as a class method in Ruby. 我是那些喜欢指出Ruby中没有类方法之类的Ruby Purists的人之一。 I am perfectly fine, though, with using the term class method colloquially, as long as it is fully understood by all parties that it is a colloquial usage . 不过, 只要各方都充分理解这是一种口语用法,那么以口语方式使用术语类方法 就可以了 In other words, if you know that there is no such thing as a class method and that the term "class method" is just short for "instance method of the singleton class of an object that is an instance of Class ", then there is no problem. 换句话说,如果你知道有没有这样的事,作为一个类的方法和术语“类方法”只是短期的“单身类的对象,它是实例的实例方法Class ”,再有就是没问题。 But otherwise, I have only seen it obstruct understanding. 但是否则,我只能看到它妨碍理解。

Let it be fully understood by all parties that the term class method is used above in its colloquial sense. 各方应完全理解,术语“ 类方法”是在其通俗意义上使用的。

Because you wrote the method not in def - end clause; 因为您def - end子句中编写该方法; you should write it like 你应该这样写

def my_method
  fields_of_model(:car).each do |attr|
    delegate attr.to_sym, "#{attr}=".to_sym, to: :car
  end
end

That is why the error message says CarRegistration::Basics:Class as opposed to CarRegistration::Basics 这就是为什么错误消息显示CarRegistration::Basics:Class而不是CarRegistration::Basics

Here is a sample code that works. 这是一个有效的示例代码。 Usually there is no need to put a class inside Module , but if you must for some reason, this is a way. 通常不需要在Module内放置一个类,但是如果您由于某种原因必须这样做,这是一种方法。

module CarRegistration
  class Basics < Object
    def run(model)
      fields_of_model(model)
    end

    private

    def fields_of_model(model)
      puts model
    end
  end
end

a = CarRegistration::Basics.new
a.run('xyz')  # => 'xyz' is printed.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 NoMethodError:#的未定义方法“类型” <Class> - NoMethodError: undefined method `type' for #<Class> 返回NoMethodError的类方法:未定义的方法Rails - Class method returning NoMethodError: undefined method Rails NoMethodError(未定义方法),但是定义了类方法 - NoMethodError (undefined method) however class method is defined NoMethodError:未定义的方法“+”用于 nil:NilClass 用于私有方法中的变量 - NoMethodError: undefined method `+' for nil:NilClass for variable in private method NoMethodError(Admin :: Notification:Class的未定义方法“ all”) - NoMethodError (undefined method `all' for Admin::Notification:Class) NoMethodError:Roo :: CSV:Class的未定义方法“生成” - NoMethodError: undefined method `generate' for Roo::CSV:Class ActionMailer — NoMethodError:MyMailer:Class的未定义方法X - ActionMailer — NoMethodError: undefined method X for MyMailer:Class 未定义方法'访问'#<Class:XYZ>(NoMethodError)[rspec] - Undefined method 'visit' for #<Class:XYZ> (NoMethodError) [rspec] ActionMailer :: Base:Class的未定义方法(NoMethodError) - undefined method for ActionMailer::Base:Class (NoMethodError) NoMethodError:BigDecimal 的未定义方法“新”:Class - NoMethodError: undefined method `new' for BigDecimal:Class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM