DEV Community

Afaq Shahid Khan
Afaq Shahid Khan

Posted on

Leveraging Mixins in Ruby on Rails: A Deep Dive

Ruby on Rails is known for its elegance and productivity. One of the powerful tools in Ruby that makes Rails development so flexible and clean is Mixins. In this article, we'll explore what Mixins are, how they work, and how you can use them to keep your Rails codebase DRY (Don't Repeat Yourself).

What are Mixins?

Mixins are a way to share reusable code across multiple classes in Ruby. They are modules that can be included in other classes to provide them with additional functionality without using inheritance. This allows you to keep your classes focused and your codebase modular.

Why Use Mixins?

  1. Code Reusability: Mixins allow you to reuse common functionality across different classes.
  2. Separation of Concerns: By moving common methods into modules, you can keep your classes smaller and more focused.
  3. Avoiding Inheritance Pitfalls: Instead of relying on complex inheritance hierarchies, you can use Mixins to share behavior across unrelated classes.

Creating a Mixin

Let's start by creating a simple Mixin. Imagine you have several models in your Rails application that need the ability to generate a unique token. Instead of duplicating the token generation code in each model, you can create a Mixin.

# app/models/concerns/tokenizable.rb
module Tokenizable
  extend ActiveSupport::Concern

  included do
    before_create :generate_token
  end

  def generate_token
    self.token = SecureRandom.hex(10)
  end
end
Enter fullscreen mode Exit fullscreen mode

Using the Mixin

Now that we have our Tokenizable module, we can include it in any model that needs this functionality.

# app/models/user.rb
class User < ApplicationRecord
  include Tokenizable
end

# app/models/order.rb
class Order < ApplicationRecord
  include Tokenizable
end
Enter fullscreen mode Exit fullscreen mode

ActiveSupport::Concern

In the example above, we used ActiveSupport::Concern to define our Mixin. ActiveSupport::Concern makes it easier to write Mixins by providing a structured way to include class methods and instance methods.

Here's an example that also includes class methods:

# app/models/concerns/tokenizable.rb
module Tokenizable
  extend ActiveSupport::Concern

  included do
    before_create :generate_token
  end

  class_methods do
    def find_by_token(token)
      find_by(token: token)
    end
  end

  def generate_token
    self.token = SecureRandom.hex(10)
  end
end
Enter fullscreen mode Exit fullscreen mode

Now you can call User.find_by_token(token) or Order.find_by_token(token) thanks to the class method defined in the Mixin.

Real-World Example: Timestampable

Let's look at a more practical example. Suppose you want to add a custom timestamp to multiple models in your application. You can create a Timestampable module.

# app/models/concerns/timestampable.rb
module Timestampable
  extend ActiveSupport::Concern

  included do
    before_save :set_custom_timestamp
  end

  def set_custom_timestamp
    self.custom_timestamp = Time.current
  end
end
Enter fullscreen mode Exit fullscreen mode

Include this Mixin in your models:

# app/models/post.rb
class Post < ApplicationRecord
  include Timestampable
end

# app/models/comment.rb
class Comment < ApplicationRecord
  include Timestampable
end
Enter fullscreen mode Exit fullscreen mode

Now, both Post and Comment models will automatically set a custom timestamp before saving.

Conclusion

Mixins are a powerful feature in Ruby that can help you keep your Rails codebase clean, DRY, and modular. By encapsulating reusable code in modules and including them in your classes, you can avoid code duplication and manage shared behavior more effectively.

Whether you're a seasoned Rails developer or just getting started, mastering Mixins will undoubtedly make your code more maintainable and elegant. Happy coding!

Top comments (0)