Repositories serve as a crucial component of the persistence layer within an application. Their primary purpose is to encapsulate the functionality provided by Rails' Active Record and expose a subset of simplified methods for querying and persisting data. By utilizing repositories, we can isolate Active Record operations to this subset, ensuring that other layers of the application only interact with the desired queries and methods.
In the context of our application, the Bike Repository now handles all operations that were previously managed by the Bike Record. This includes tasks such as finding, creating, and deleting records. By consolidating these responsibilities within the repository, we establish a clear separation of concerns and promote maintainability and flexibility within our codebase.
require_relative "../db/records/bike"
require "active_record"
module Bikes
class RecordNotFound < StandardError
end
class Repository
def initialize
setup_database
end
def all
Db::Records::Bike.all
end
def create(name:)
Db::Records::Bike.create(name: name)
end
def find(id:)
Db::Records::Bike.find(id)
rescue ActiveRecord::RecordNotFound
raise RecordNotFound.new
end
def update(id:, params:)
record = find(id: id)
record.update(params)
record
end
def delete(id:)
record = find(id: id)
record.destroy!
end
private
def setup_database
ActiveRecord::Base.configurations = YAML.load_file("db/configuration.yml")
ActiveRecord::Base.establish_connection(ENV["RACK_ENV"].to_sym)
end
end
end
It’s worth noting that the term “Records” is now used to refer to Active Record objects. This change is reflected by moving the previous Bike class from the “db” directory to “db/records” and placing it within the appropriate module. This reorganization further enhances the modularity and organization of our codebase.
require "active_record"
module Db
module Records
class Bike < ActiveRecord::Base
has_many :components
end
end
end
However, it’s important to acknowledge that Active Record is not completely encapsulated at this stage. The repository still returns Record objects that are relied upon by controllers and views. These Record objects serve multiple purposes within the application. In certain actions, such as “new” and “edit,” they represent user input, capturing the data entered by the user. On the other hand, in actions like “index” and “show,” they embody the actual persisted entities within the system. Additionally, Record objects hold any validation errors that may occur during attempted persistence operations.
By introducing the BikeRepository
, we achieve several benefits:
- Modularity: The repository isolates the database interactions, making it easier to understand, test, and modify the persistence layer without affecting other parts of the application.
- Separation of Concerns: The repository separates the concerns of querying and persisting data from the business logic and the user interface. This promotes a cleaner architecture and enhances code organization.
- Testability: By abstracting the database interactions behind a repository interface, we can easily write unit tests for the other layers of the application. We can mock the repository’s methods to simulate different scenarios and verify the behavior of the calling code.
- Flexibility: Repositories provide a flexible interface that can adapt to changing requirements. If the underlying data storage needs to be replaced or modified, the repository can be updated accordingly without affecting other parts of the application.
In conclusion, repositories play a vital role in simplifying data persistence in the applications. By encapsulating Active Record within a subset of methods, repositories provide a focused and intuitive interface for querying and persisting data. They promote modularity, separation of concerns, testability, and flexibility. When used effectively, repositories contribute to a more maintainable, scalable, and robust application architecture. The whole code where I added repositories into the app is on github