Reputation: 2799
So im having this weird issue for some reason i dont know why it is happening.
So, i have this extension in conifg/initializers/has_friendly_token.rb
ActiveRecord::Base.define_singleton_method :has_friendly_token do
extend FriendlyId
friendly_id :token
before_validation :set_unique_token, if: :set_token?
define_method :set_token? do
new_record? || saved_change_to_token?
end
define_method :set_unique_token do
table_name = self.model_name.route_key
scope = persisted? ? self.class.where("#{table_name}.id != ?", id) : self.class.default_scoped
while token.nil? || scope.where(token: token).exists?
self.token = SecureRandom.base58(24)
end
end
end
And I'm using it in two different models
class Business < ApplicationRecord
include Colorful, Channels, Rails.application.routes.url_helpers
has_friendly_token
end
and
class Conversation < ApplicationRecord
has_friendly_token
include AASM, Colorful, Rails.application.routes.url_helpers
end
the thing is, whenver i try to to run i get this error
`method_missing': undefined local variable or method `has_friendly_token' for Business (call 'Business.connection' to establish a
connection):Class (NameError)
Did you mean? has_secure_token
but it works in conversation
. Any ideas why this happenes?
Upvotes: 0
Views: 55
Reputation: 102423
I can't see a good reason to use an initializer to monkeypatch ActiveRecord::Base here in the first place. Instead create a module and extend your ApplicationRecord class with it as this is simply a "macro" method.
module FriendlyToken
def has_friendly_token
extend FriendlyId
friendly_id :token
before_validation :set_unique_token, if: :set_token?
define_method :set_token? do
new_record? || saved_change_to_token?
end
define_method :set_unique_token do
table_name = self.model_name.route_key
scope = persisted? ? self.class.where("#{table_name}.id != ?", id) : self.class.default_scoped
while token.nil? || scope.where(token: token).exists?
self.token = SecureRandom.base58(24)
end
end
end
end
class ApplicationRecord < ActiveRecord::Base
extend FriendlyToken
end
Unlike a monkeypatch its easy to test this code and it will be picked up by documentation tools like rdoc or yard as well as coverage tools.
You could also just simply write it as a concern since your macro method does not take any arguments anyways:
module FriendlyToken
extend ActiveSupport::Concern
included do
extend FriendlyId
friendly_id :token
before_validation :set_unique_token, if: :set_token?
end
def set_token?
new_record? || saved_change_to_token?
end
def set_unique_token?
table_name = self.model_name.route_key
scope = persisted? ? self.class.where("#{table_name}.id != ?", id) : self.class.default_scoped
while token.nil? || scope.where(token: token).exists?
self.token = SecureRandom.base58(24)
end
end
end
class Business < ApplicationRecord
include Colorful,
Channels,
Rails.application.routes.url_helpers,
FriendlyToken
end
The advantage here is easier debugging since the methods are not defined dynamically.
See 4 Ways To Avoid Monkey Patching.
Upvotes: 1