I have the following code in a rails concern:
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
which is used in these classes:
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
However, when I try to call the method, I get an undefined method error. Any ideas why this may be? Here is an example of where I am calling the method:
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
here is an example of the error I am getting (from running my specs):
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)>'
The specfile in question:
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
EDIT - I made the following changes to my concern as per goddamnyouryan's answer:
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
but I get the following error:
Users/karuna/Documents/Projects/catalog/app/models/concerns/destroy_exclusion.rb:5:in `<module:DestroyExclusion>': undefined method `class_methods' for DestroyExclusion:Module (NoMethodError)
If you want to define class methods inside your concern:
For Rails version < 4.2.0,
module DestroyExclusion
extend ActiveSupport::Concern
module ClassMethods
def destroy_exclusion_on_category_deletion(etc)
# some code
end
end
end
For Rails version >= 4.2.0
module DestroyExclusion
extend ActiveSupport::Concern
class_methods do
def destroy_exclusion_on_category_deletion(etc)
# some code
end
end
end
Ruby way of doing thing
module DestroyExclusion
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def destroy_exclusion_on_category_deletion(etc)
# some code
end
end
end
In Rails 4 (and Rails 5), if you want to define a class method inside your concern, then you have to just define that method inside a:
module ClassMethods
. . .
end
which is what you are looking for. The code contained within this module ClassMethods
block will be added to the Class itself.
So, your modified concern code should look like this:
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 has a simple and nice explanation about concerns in Rails 4!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With