Open yelvert opened 6 years ago
Hi @yelvert!
First off, very nice looking gem
Thank you ;)
..cloning records from a separate database ...could this gem handle that use case out of the box?
An interesting case and we didn't think about this when we developed Сlowne. We always use the source class as the base class for cloning and it can't be overridden, but we have a magic init_as declaration.
So, please, look this proof of concept (especially AsAlien
module):
At first, define models and schemas
require 'clowne'
require 'activerecord'
require 'sqlite3'
class ApplicationRecord < ::ActiveRecord::Base
self.abstract_class = true
establish_connection(adapter: 'sqlite3', database: 'file:memdb2?mode=memory')
end
class Widget < ApplicationRecord; end
module GuestHouse
class ApplicationRecord < ::ActiveRecord::Base
self.abstract_class = true
establish_connection(adapter: 'sqlite3', database: 'file:memdb1?mode=memory')
end
class Widget < ApplicationRecord; end
end
ActiveRecord::Schema.define do
self.verbose = false
ApplicationRecord.connection.create_table :widgets, force: true do |t|
t.string :name, null: false
t.string :country, null: false
end
GuestHouse::ApplicationRecord.connection.create_table :widgets, force: true do |t|
t.string :name, null: false
t.string :country, null: false
end
end
Then implement cloners
module AsAlien
def self.included(base)
base.class_eval do
init_as do |source, params|
target_class =
if target_scope = params[:target_scope]
target_scope.const_get(source.class.name.demodulize)
else
source.class
end
target_class.new(source.attributes)
end
end
end
end
class WidgetCloner < Clowne::Cloner
include AsAlien
finalize do |_source, record|
record.name = "[cloned] " + record.name
end
end
class GuestHouse::WidgetCloner < Clowne::Cloner
include AsAlien
finalize do |_source, record|
record.name = "[guest cloned] " + record.name
end
end
And call it
w1 = Widget.create(name: 'News', country: 'ru')
w2 = GuestHouse::Widget.create(name: 'Weather', country: 'us')
# WidgetCloner:
WidgetCloner.call(w1)
=> #<Widget:0x00007fbb349c1f20 id: 1, name: "[cloned] News", country: "ru">
WidgetCloner.call(w2)
=> #<GuestHouse::Widget:0x00007fbb332c5c40 id: 1, name: "[cloned] Weather", country: "us">
WidgetCloner.call(w2, target_scope: Object)
=> #<Widget:0x00007fbb3209cd98 id: 1, name: "[cloned] Weather", country: "us">
# GuestHouse::WidgetCloner:
GuestHouse::WidgetCloner.call(w1)
=> #<Widget:0x00007fbb349311f0 id: 1, name: "[guest cloned] News", country: "ru">
GuestHouse::WidgetCloner.call(w2)
=> #<GuestHouse::Widget:0x00007fbb348f3b70 id: 1, name: "[guest cloned] Weather", country: "us">
GuestHouse::WidgetCloner.call(w1, target_scope: GuestHouse)
=> #<GuestHouse::Widget:0x00007fbb348b9ec0 id: 1, name: "[guest cloned] News", country: "ru">
Since we can proxy the parameters through all associations, this will allow you to clone objects under one scope (DB). I hope this will be useful for you!
First off, very nice looking gem, I actually just started work on something very similar, except my use case involves cloning records from a separate, but (mostly) identical database. I'm currently using a separate
ApplicationRecord
base class, for handling the alternate models to clone from, that looks like this.So, if I have:
Then
Widget
s can be cloned fromGuestHouse::Widget
sCould this gem handle that use case out of the box, or would it need some additional development, and if so, could you point me to a starting place?