我在轨道问题中有以下代码:
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)
答案 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,这对我来说非常头疼!