Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Databases #18

Open
yelvert opened this issue Feb 27, 2018 · 1 comment
Open

Multiple Databases #18

yelvert opened this issue Feb 27, 2018 · 1 comment
Labels
awaiting response Awaiting response from the author

Comments

@yelvert
Copy link

yelvert commented Feb 27, 2018

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.

module GuestHouse
  class ApplicationRecord < ::ActiveRecord::Base
    self.abstract_class = true
    establish_connection "guest_house_#{Rails.env}".to_sym

  end
end

So, if I have:

class Widget < ApplicationRecord
end

class GuestHouse::Widget < GuestHouse::ApplicationRecord
end

Then Widgets can be cloned from GuestHouse::Widgets

Could 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?

@ssnickolay ssnickolay added the awaiting response Awaiting response from the author label Feb 28, 2018
@ssnickolay
Copy link
Collaborator

ssnickolay commented Feb 28, 2018

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting response Awaiting response from the author
Projects
None yet
Development

No branches or pull requests

2 participants