Sinscary Sinscary - 4 months ago 20
Ruby Question

how to mixin gem-modules in ruby-on-rails model

I am building a gem in which i have a module

OtpGenerator
. inside this module i have methods like
generate_otp
,
verify_otp
etc. This is just a begining for me and its very simple gem only to generate and verify and save and send, nothing else. Now anyone who uses this gem will have to include this module in their model. for e.g. there is a
user
model. now what i want is first i will create a instance

user = User.new(params[:user])


now i need to do the operation
user.generate_otp
, this will assign otp related things in the activerecord instance.

after that
user.save
, which is also fine.

But i also want a function
generate_otp!
, which will do all task like generates otp, than save it and sends it. My problem is that i am not getting how to achieve this functionality.

Note: I am very new to ruby. and really getting confused with mixins.

here is my code for
otp.rb
file

require 'securerandom'

module OtpGenerator
def generate_otp
SecureRandom.hex(4)
end

def verify_otp(generated, otp, otp_expiry_time)
if matches?(generated, otp) and !expired?(otp_expiry_time)
true
else
false
end
end

def regenerate_otp
generate_otp
end

def matches?(generated, otp)
if otp == generated
true
else
false
end
end

def expired?(otp_expiry_time)
if otp_expiry_time < Time.now
true
else
false
end
end

#custom error messages, Todo: still needs to clean
def invalid_code
if !matches?(generated, otp)
errors.add(:invalid_code, "you have entered a invalid code")
end
end

def code_expired
if expired?(otp_expiry_time)
errors.add(:otp_expired, "otp code expired")
end
end
end


This code is still in development, i just want to know that how to implement
generate_otp!
function, which will do all three operation,i.e,
(1) generates otp(user.generate_otp)
(2) saves otp(user.save)
(3) sends otp (i have created the send function, so thats not a problem.)

Answer

If this is a mixin in your model, then your model should also have access to it. Here is what I mean:

class User
  include OtpGenerator
end

module OtpGenerator
...
  def generate_otp!
    generate_otp
    save
    send_generated_otp
  end
end

When you call User.find(45).generate_otp!

That would work because of the way inheritances work in Ruby. Once the module is included within a class, it inherits all the methods of the module and the module has access to the context of the included class.

Hope that answers your question

Comments