Reputation: 171
Beginner ruby/rails question here. I have a method That I am currently using in my "User" model.
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
I want to reuse the same method in a different model say my Account model.
Where is a good place to put code like this to be shared between models? Also, in order to get the calling class would I just use "self.class"?
Thanks
Upvotes: 9
Views: 3812
Reputation: 31
For code reusability, we use modules. The more common usage of modules in Rails is to share common code. so the answer is
lib/some_token_generation.rb
module SomeTokenGeneration
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
models/some_model1.rb
class SomeModel1
include SomeTokenGeneration
end
or models/some_model2.rb
class SomeModel2
include SomeTokenGeneration
end
The include method adds any methods in the module as instance methods to the class
Let’s look at a scenario where two classes could share an instance method.
So you can use that method in both models as models/some_model1.rb
class SomeModel1
include SomeTokenGeneration
def some_method1
self.generate_token(column)
end
end
or models/some_model2.rb
class SomeModel2
include SomeTokenGeneration
def some_method2
self.generate_token(column)
end
end
Upvotes: 0
Reputation: 630
If you are ever writing the same method twice, you are right that it's probably a sign of writing bad code. If it were me, I would create an abstract class that is a parent class to both Account and User. Make Account and User inherit from this parent class, and put all of the shared logic in that parent class. Then Account and User will automatically have access to that shared logic.
You will want to look up how to make abstract classes in rails. Once you've made the new parent abstract class, make sure Account and User inherit from the parent class instead of ActiveRecord::Base like so:
class Account < NewAbstractClass
end
class user < NewAbstratClass
end
I am neither agreeing nor disagreeing with the above or below answers, through using concerns or through using modules. However, this is the way that I have solved this problem before in the past, and this is a good object orient way to try and solve the problem of shared logic between multiple classes.
Upvotes: 1
Reputation: 3371
Rails 4 concerns
are here to do this job. http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
app/models/user.rb
:
class User < ActiveRecord::Base
include TokenGenerator
def foo
$stderr.puts self.class.generate_token("bar")
end
end
app/models/account.rb
:
class Account < ActiveRecord::Base
include TokenGenerator
class << self
def bar
return generate_token("foo")
end
end
end
app/models/concerns/token_generator.rb
module TokenGenerator
extend ActiveSupport::Concern
module ClassMethods
def generate_token(c)
return "some_thing"
end
end
end
Upvotes: 10