1

I've been reading about the repository pattern: https://blog.spacesnottabs.io/2019/01/30/the-repository-pattern-for-ruby/ and it would be great to have the ability to convert an ActiveRecord object and convert it to an ActiveModel object so that it maintains methods like .attributes and its validations, but loses all of the methods that would make a call to the database like .save or .items.

E.g. Consider this class:

class TodoList < ActiveRecord::Base
  has_many :items

  validates :name, presence: true
end

I would like to be able to do something like:

> todoList = TodoList.first # first AR record from the database
> todoListModel = todoList.to_ar_model # converts from ActiveRecord to ActiveModel
> todoListModel.class
=> ActiveModel
> todoListModel.save
=> NoMethodError
> todoListModel.items
=> NoMethodError
> todoListModel.valid?
=> true

I know of the to_model method, but it's not what I want: https://api.rubyonrails.org/classes/ActiveModel/Conversion.html#method-i-to_model

stwr667
  • 1,566
  • 1
  • 16
  • 31

1 Answers1

1

Not sure if this is a good idea, but I implemented it.

class TodoListModel
  include ActiveModel::Model
  include ActiveModel::Attributes

  TodoList.columns_hash.each do |name, column|
    attribute(
      name,
      TodoList.connection.lookup_cast_type_from_column(column),
      default: column.default
    )
  end
end

todo_list = TodoList.first
model = TodoListModel.new(todo_list.attributes)

TodoListModel has all the same columns with correct types and default values. It will not have the same validations by default, you'll have to either implement them twice or share code between the two.

Siim Liiser
  • 3,860
  • 11
  • 13
  • Thanks Siim. It's a solution for sure. And I'd probably mix in the validations to DRY up the code. I'm still wondering if there's something that's more core to ActiveRecord or ActiveModel that could be used to achieve this. E.g. something that may strip away the persistence methods of an AR class rather than build a new ActiveModel from scratch. – stwr667 Jul 28 '20 at 12:29