I have a module in lib folder. Where I have created a InstanceMethods module.
require 'memoist'
extend Memoist
module MyStudentMethods
def self.included base
base.send :include, InstanceMethods
end
module InstanceMethods
def find_student(user_id)
self.student.find{|student| student.user_id == user_id }
end
memoize :find_student
end
end
I am using this module in my model.
require_dependency 'my_student_methods'
class Student < ActiveRecord::Base
# previously I was using memoize like below commented out code
# require 'memoist'
# extend Memoist
include MyStudentMethods
end
But when I start rails server it through an error:
/home/Projects/school/lib/my_student_methods.rb:12:in `<module:InstanceMethods>': undefined method `memoize' for MyStudentMethods::InstanceMethods:Module (NoMethodError)
Issue: How can I memoize the module method?.
Try moving extend Memoist into your module. Like this:
module InstanceMethods
extend Memoist
...
module InstanceMethods
extend Memoist
...
Related
I'm learning how to write a gem. I want to add some methods that I will use in a User model in Rails.
# app/models/user.rb
class User
include Mongoid::Document
include Authme::Model # here's my gem.
field :password_digest, type: String
end
# Gemfile
gem 'authme'
Now, inside my gem I have the following:
- authme
- lib
+ authme
- model.rb
- authme.rb
Here are the contents of the gem.
# lib/authme.rb
require 'authme/version'
require 'authme/model'
module Authme
end
# lib/authme/model.rb
module Authme
module Model
extend ActiveSupport::Concern
included do
include ActiveModel::SecurePassword
has_secure_password validations: false
before_create :create_session_token
end
module ClassMethods
def new_session_token
SecureRandom.urlsafe_base64
end
def encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
end
private
def create_session_token
self.session_token = self.class.encrypt(self.class.new_session_token)
end
end
end
I add this to my gemspec:
spec.add_dependency "activesupport", "~> 4.0.1"
To test this, inside the terminal, I tried User.new_session_token and got this error:
NoMethodError: undefined method `new_session_token' for User:Class
What am I doing wrong? I really want to test this, but I'm out of my depth. I'm not sure how to test that the class User has the included the gem module.
The problem is that you're creating Authme::Model and Authme::Model::ClassMethods but you're never actually adding new_session_token as class methods of Authme::Model.
If you want to add these methods onto Authme::Model you need to do something like
module Authme
module Model
module ClassMethods
# define all of your class methods here...
end
extend ClassMethods
end
end
The key part here is the Object#extend.
I'm trying to build a gem and I want to define a method my_method inside the gem and use it inside a model.
Example:
class MyModel < ActiveRecord::Base
my_method
end
My gem:
#lib/my_gem.rb
require "my_gem/model_inclusions"
module MyGem
end
#lib/my_gem/model_inclusions.rb
module MyGem
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def my_method
end
end
end
When I try the example it gives me undefined method 'my_method' for <Class:0x00000045434> (NoMethodError)
module NumberInternationalizer
def my_method
...
end
end
ActiveRecord::Base.send :extend, NumberInternationalizer
I am writing my first Rails gem, which adds a method to ActiveRecord. I can't seem to figure out a simple way to call other methods from within the method I am adding to ActiveRecord. Is there a pattern for this I should be using?
module MyModule
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def my_class_method
# This doesn't work
some_utility_method
end
end
def some_utility_method
# Do something useful
end
end
ActiveRecord::Base.send(:include, MyModule)
Once you've included MyModule, ActiveRecord::Base will have my_class_method as a class method (equivalently, an instance method of the Class object ActiveRecord::Base), and some_utility_method as an instance method.
So, inside my_class_method, self is the Class ActiveRecord::Base, not an instance of that class; it does not have some_utility_method as an available method
Edit:
If you want a utility method private to the Module, you could do it like this:
module MyModule
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def my_class_method
# This doesn't work
MyModule::some_utility_method
end
end
def self.some_utility_method
# Do something useful
end
end
ActiveRecord::Base.send(:include, MyModule)
I love ActiveSupport::Concern.
It makes it easy to add functionality to your classes, with a nice syntax.
Anyways, in Rails 3.2, the InstanceMethods module has been deprecated. If I understood correctly, we should just define our methods in the included block (actually it's just in the body of the module):
# edit: don't do this! The method definition should just be in the body of the module
included do
def my_method; end
end
I was just wondering if anyone knows why they decided to do that?
Let's look at the example you linked first.
module TagLib
extend ActiveSupport::Concern
module ClassMethods
def find_by_tags()
# ...
end
end
module InstanceMethods
def tags()
# ...
end
end
end
When you include TagLib into your class AS Concern automatically extends the class with ClassMethods module and includes InstanceMethods module.
class Foo
include TagLib
# is roughly the same as
include TagLib::InstanceMethods
extend TagLib::ClassMethods
end
But as you may noticed we are already including TagLib module itself so the methods defined within it are already available as instance methods on the class. Why would you want to have a separate InstanceMethods module then?
module TagLib
extend ActiveSupport::Concern
module ClassMethods
def find_by_tags()
# ...
end
end
def tags()
# ...
end
end
class Foo
include TagLib
# does only `extend TagLib::ClassMethods` for you
end
I have found a lot of information about adding form helper methods (see one of my other questions), but I can't find anything about adding helper methods as if they were defined in application_helper.rb.
I've tried copying application_helper.rb from a rails app into the gem but that didn't work.
I've also tried:
class ActionView::Helpers
..but that produces an error.
Create a module somewhere for your helper methods:
module MyHelper
def mymethod
end
end
Mix it into ActionView::Base (such as in init.rb or lib/your_lib_file.rb)
ActionView::Base.send :include, MyHelper
To extends #sdbrown's excellent Answer to Rails 4:
# in in lib/my_rails_engine.rb
require 'my_rails_engine/my_rails_helper.rb'
require 'my_rails_engine/engine.rb'
And
# in lib/my_rails_engine/engine.rb
module MyRailsEngine
class Engine < ::Rails::Engine
initializer "my_rails_engine.engine" do |app|
ActionView::Base.send :include, MyRailsEngine::MyRailsHelpers
end
end
end
and finally
# in lib/my_rails_engine/my_rails_helper.rb
module MyRailsEngine
module MyRailsHelpers
# ...
def your_helper_here
end
end
end