从私人方法中的nomethoderror(未定义的方法)



为什么我不能在同类中使用私人方法?如何修复我的代码以防止错误?

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

错误

nomethoderror(未定义的方法`fields_of_model'for carRegistration ::基础:班级):

我认为您在这里遇到了许多问题。

首先,您将fields_of_model定义为实例方法,此处:

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

,但是您正在尝试从班级打电话:

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

因此,您需要将fields_of_model作为类方法,并在调用它之前对其进行定义。类似:

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

我认为,您还将遇到该car_structure变量的问题,因为该类方法的范围不超出范围。因此,我认为您需要进行类级实例变量。因此,请尝试一下:

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

请注意,我使用private :fields_of_model进行了类方法,:fields_of_models私有。

为了演示整个过程,我插了此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

在运行时,哪个产生:

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

顺便说一句,在def -end之外的班级中有此代码很好,而不是问题的根源。实际上,这很正常。

另外,我会注意到JörgWMittag希望说:

我是那些喜欢指出的红宝石纯粹主义者之一,在Ruby中没有类方法。不过,我完全很好,只要所有各方都完全理解了这是口用使用, colloququalial colloququal 。换句话说,如果您知道没有类方法之类的东西,而术语"类方法"只是" singleton" singleton类的实例方法的简短,则是一个实例Class",然后没有问题。但是否则,我只看到它阻碍了理解。

所有各方都完全理解了术语 class方法在俗语中使用。

,因为您在 def - end rause中写下了方法不是;你应该像

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

这就是为什么错误消息说CarRegistration::Basics:Class而不是CarRegistration::Basics

这是有效的示例代码。通常,无需在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.

最新更新