为问题添加了方法,但是获取了未定义的方法错误

时间:2015-08-12 07:08:42

标签: ruby-on-rails ruby ruby-on-rails-4

我在轨道问题中有以下代码:

module DestroyExclusion
  extend ActiveSupport::Concern

  def self.destroy_exclusion_on_category_deletion(academy_id,product_id,category_id)
    if(category_id == nil)
      if exists?(:academy_id => academy_id, :product_id => product_id)
        where(:academy_id => academy_id, :product_id => product_id).first.destroy
      end
    elsif(product_id == nil)
      if exists?(:academy_id => academy_id, :category_id => category_id)
        where(:academy_id => academy_id, :category_id => category_id).first.destroy
      end
    end

  end
end

在这些类中使用:

class ExcludeProduct < ActiveRecord::Base
  include DestroyExclusion
  belongs_to :academy
  belongs_to :product


end

class ExcludeCategory < ActiveRecord::Base
  include DestroyExclusion
  belongs_to :academy
  belongs_to :category

end

但是,当我尝试调用该方法时,我得到一个未定义的方法错误。 任何想法为什么会这样?以下是我调用方法的示例:

  def destroy_exclusions
    category_record = Category.find(self.category_id)
    if !self.product_id.blank?
      academies = category_record.parent_academies
      academies.each do |academy|
        ExcludeProduct.destroy_exclusion_on_category_deletion(academy.id, self.product_id,nil)
      end
    else
      products = category_record.child_products
      products.each do |product|
        ExcludeProduct.destroy_exclusion_on_category_deletion(self.academy_id, product.id,nil)
      end
    end
  end

这是我得到的错误示例(来自运行我的规范):

 1) AcademyCategoryProduct successfully destroys exclusions
     Failure/Error: category_product.destroy_exclusions
     NoMethodError:
       undefined method `destroy_exclusion_on_category_deletion' for #<Class:0x007fc532c0ae50>
     # /Library/Ruby/Gems/2.0.0/gems/activerecord-4.1.6/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
     # ./app/models/academy_category_product.rb:13:in `block in destroy_exclusions'
     # /Library/Ruby/Gems/2.0.0/gems/activerecord-4.1.6/lib/active_record/relation/delegation.rb:46:in `each'
     # /Library/Ruby/Gems/2.0.0/gems/activerecord-4.1.6/lib/active_record/relation/delegation.rb:46:in `each'
     # ./app/models/academy_category_product.rb:12:in `destroy_exclusions'
     # ./spec/models/academy_category_product_spec.rb:25:in `block (2 levels) in <top (required)>'

有问题的specfile:

require 'rails_helper'

describe AcademyCategoryProduct do

  let(:product) { FactoryGirl.create(:academy_product) }
  let(:category) { FactoryGirl.create(:category) }
  let(:subcategory) {FactoryGirl.create(:category, :parent_id => category.id)}
  let(:academy) { FactoryGirl.create(:academy) }
  let(:category_product) { FactoryGirl.create(:academy_category_product, :category_id => subcategory.id, :product_id => product.id, :academy_id => nil) }
  let(:academy_category) { FactoryGirl.create(:academy_category_product, :category_id => category.id, :academy_id => academy.id, :product_id => nil ) }
  let(:exclude_product) { FactoryGirl.create(:exclude_product, :product_id => product.id, :academy_id => academy.id) }
  let(:exclude_category) { FactoryGirl.create(:exclude_category, :category_id => subcategory.id, :academy_id => academy.id) }

  before(:each) do
    category.reload
    academy.reload
    exclude_category.reload
    exclude_product.reload
    category_product.reload
    academy_category.reload
    exclude_product.reload
  end

  it "successfully destroys exclusions" do
    category_product.destroy_exclusions
    expect(ExcludeProduct.first).to eql(nil)
  end

  it "successfully destroys category exclusions" do
    academy_category.destroy_category_exclusions
    expect(ExcludeCategory.first).to eql(nil)
  end
end

编辑 - 根据goddamnyouryan的回答,我对我的关注做了以下更改:

require 'active_support/concern'
module DestroyExclusion
  extend ActiveSupport::Concern

  class_methods do

    def self.destroy_exclusion_on_category_deletion(academy_id,product_id,category_id)
      if(category_id == nil)
        if exists?(:academy_id => academy_id, :product_id => product_id)
          where(:academy_id => academy_id, :product_id => product_id).first.destroy
        end
      elsif(product_id == nil)
        if exists?(:academy_id => academy_id, :category_id => category_id)
          where(:academy_id => academy_id, :category_id => category_id).first.destroy
        end
      end
    end
  end
end

但是我收到以下错误:

Users/karuna/Documents/Projects/catalog/app/models/concerns/destroy_exclusion.rb:5:in `<module:DestroyExclusion>': undefined method `class_methods' for DestroyExclusion:Module (NoMethodError)

4 个答案:

答案 0 :(得分:14)

在Rails 4(和Rails 5)中,如果你想在你关注的内部定义一个类方法,那么你必须在一个内部定义该方法:

module ClassMethods
 . . . 
end

这就是你要找的东西。此module ClassMethods块中包含的代码将添加到类本身。

因此,您修改后的关注代码应如下所示:

module DestroyExclusion
  extend ActiveSupport::Concern

  module ClassMethods
    def destroy_exclusion_on_category_deletion(academy_id,product_id,category_id)
      if(category_id == nil)
        if exists?(:academy_id => academy_id, :product_id => product_id)
          where(:academy_id => academy_id, :product_id => product_id).first.destroy
        end
      elsif(product_id == nil)
        if exists?(:academy_id => academy_id, :category_id => category_id)
          where(:academy_id => academy_id, :category_id => category_id).first.destroy
        end
      end

    end
  end
end

This tutorial对Rails 4中的问题有一个简单而好的解释!

答案 1 :(得分:7)

您需要将这些方法嵌套在class_methods do块中。请参阅documentation for ActiveSupport::Concern

类似的东西:

module DestroyExclusion
  extend ActiveSupport::Concern

  class_methods do
    def destroy_exclusion_on_category_deletion(etc)
      # omitted
    end
  end
end

答案 2 :(得分:2)

如果要在关注范围内定义类方法:

对于Rails版本<4.2.0,

module DestroyExclusion
  extend ActiveSupport::Concern

  module ClassMethods
    def destroy_exclusion_on_category_deletion(etc)
      # some code
    end
  end
end

对于Rails版本> = 4.2.0

module DestroyExclusion
  extend ActiveSupport::Concern

  class_methods do
    def destroy_exclusion_on_category_deletion(etc)
      # some code
    end
  end
end

Ruby的做事方式

module DestroyExclusion
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def destroy_exclusion_on_category_deletion(etc)
      # some code
    end
  end
end

答案 3 :(得分:0)

我有一个类似的问题,K M Rakibul Islam的回答是99%正确,但我必须在我的模型关注中包含以下方法才能让ClassMethod为我工作。

def self.included(base)
   base.extend(ClassMethods)
end

谢谢@ K-M-Rakibul-Islam,这对我来说非常头疼!