1

I'm trying to build inheritance in my app .

In fact it's simple i have several models , and some of them need to be 'archive' , it simply means that i gonna move data from my database public schemat to an archive schemat ( same database ).

Each models have a methods 'save'itself'OnArchive by example :

 def saveContactArchive(contact)
record = ArchContacts.new
record.id=contact.id
record.information_id=contact.information_id
record.is_internal = contact.is_internal if (contact.is_internal != nil)
record.type_contact_id = contact.type_contact_id if (contact.type_contact_id != nil)
record.user_id = contact.user_id if (contact.user_id != nil)
record.info_readed = contact.info_readed if (contact.info_readed != nil)
record.not_received = contact.not_received if (contact.not_received != nil)
record.society_name = contact.society_name if (contact.society_name != nil)
record.person_name = contact.person_name if (contact.person_name != nil)
record.email = contact.email if (contact.email != nil)
record.receipt = contact.receipt if (contact.receipt != nil)
record.receipt_confirmed = contact.receipt_confirmed if (contact.receipt_confirmed != nil)
record.created_at = contact.created_at if (contact.created_at != nil)
record.updated_at = contact.updated_at if (contact.updated_at != nil)



id = contact.id
if (!existOnArchive(id))
  return record.save
else
  return true
end


  end

And SOME of models have a methodes save'arrayOf'OnArchive by example :

 def saveContactsArchive(contacts)
resultContact = false
for c in contacts

  if(c.id != nil)
    resultContact = saveContactArchive(c)
  else
    resultContact = true
  end
  if(!resultContact)
    ArchiveLogs.debug("Sauvegarde d'un contact sur l archive echoue, contact concerne  "+c.inspect)
  end
end
return resultContact
   end

I'm trying to create a parent class for all those Models , called Archive. This class woud define 2 methods

 class Archive
  def saveOnArchive(element)
    "Save on archive"
  end
  def saveArrayOnArchive(elements)
    "Save an array on archive"
  end
 end

saveArrayOnArchive follow the same logic for all models , like for saveContactsArchive ; loop on array , for each element call saveOnArchive, write logs if error .

My questions ;

1)is that better to create a modular saveArrayOnArchive and how to call children method saveOnArchive from parent class?

2)What my models gonna look like ? have they to redifine every methods ? calling super if they don't add anything to parent method?

3)is that even possible since my models are already childreen from activerecord class ArchContacts < ActiveRecord::Base ----EDIT---- Why shoud my models be children of ActiveRecord::Base (i just followed an other dev model without brain ....) ----EDIT----

3 in 1 ) How to achieve this if someone understood me ... any help apricieted

2 Answers 2

1

In your case they all seem to have the same attributes, so you could make good use of the method #becomes which creates a new instance of a different class with the same attributes of the current class, for example

contact = Contact.first
archived_contact = contact.becomes ArchContact
archived_contact.save

This will create the archived contact and save you all the pain of copying each attribute.

Let me first explain how method calling works, each instance has a tree that a method call bubbles up till it finds the method you are looking for, so if you call saveOnArchive the instance will look at it's class and check if there's a method with that name, if not then it checks the included modules, if not it checks the SuperClass of the class, then the SuperClass's modules, all the way up to the tree and then falls into the method_missing method which prints the error saying that the method is not found.

I don't think it's necessary for you to create an object and inheret it for just 2 methods, you could include a module that has these methods, for example here's the archive module.

module Archive
  ef method_1
  end
  def method_2
  end
end

Then include it in the Contact class

class Contact < ActiveRecord::Base
  include Archive
end

Now your Contact class has method_1 and method_2 because they exist in the look up tree, but since you have different classes and each archive in differnet tables, you could add a little dynamic method to handle this, here's a small example

module Archive
  def self.included(klass)
    klass.instance_eval do
      define_method "save_#{klass.name}_archive" do
        self.becomes "#{klass.name}Archive".constantize
      end
    end
  end
end

The module uses the class that included it and gets its name to define dynamic methods, in this case the contact model will have a save_contact_archive method that returns an instance of ContactArchive filled with it's attributes, you can then save that object.

But if a class called User inculded the Archive module, the methods will be called save_user_archive and it saves to an object called UserArchive.

A simple usage of this would be

contact = Contact.first
archived_contact = Contact.save_contact_archive
archived_contact.save

I hope I made this simple, if you need further help please ask.

Sign up to request clarification or add additional context in comments.

1 Comment

That looks awesome !!! perfect solution for my needs , i gonna need some times to understand everything but i go for it :) ! thank you !!
0

You can't inherit from multiple classes. You can however put this functionality in a module, for example

module Archivable
  extend ActiveSupport::Concern
  included do
    class_attribute :archive_class
  end

  def save_in_archive
    unless archive_exists?
      archive_class.create(attributes.reject {|_, value| value.nil?}
    end
  end

  #implement other methods such as archive_exists
end

You classes could then do

class Contact
  include Archivable
  self.archive_class = ArchContacts

end

You could do things like infer the archive class name from the name of the model or add a method to active record that would include your module and configure it (like acts_as_list) but the basic approach is the same.

I have changed your method to not set the attributes one by one - if not then you wouldn't be able to reuse the archive method. If you don't want all attributes to be archived then I'd add another class_attribute that would either be a whitelist or a blacklist of attribute names, that you can slice the attributes hash with.

You might also consider setting ArchContacts.record_timestamps = false or else rails will be updating the updated_at and created_at columns, which you presumably don't want.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.