Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Archive objects don't mimic the methods in the original object #2

Closed
nielsm opened this Issue · 6 comments

3 participants

@nielsm

class Foo < ActiveRecord::Base
has_many :bar
belongs_to :account

def name
return "#{first_name} #{last_name}"
end
end

Build a foo:
foo = Foo.create(:first_name => "John", :last_name => "Adams", :account_id => 1)
bar = Bar.new
bar.foo = foo
bar.save
foo_id = foo.id
bar_id = bar.id

Now we can call foo.bars & get back the bar created. If we call foo.name, we get "John Adams". If we call foo.account, we get Account with id = 1. If we call foo.destroy, it is moved to the archive table. However, if we now load it as:

foo = Foo::Archive.find(foo_id)
foo.name #NoMethodError: undefined method name' for #<Foo::Archive:0x105ffdcb8>
foo.bars #NoMethodError: undefined method
bars' for #Foo::Archive:0x105ffdcb8
foo.account #NoMethodError: undefined method `account' for #Foo::Archive:0x105ffdcb8

Is there any way to archive it in a way that the methods are still maintained? How can we handle relationships, such that they are also maintained?

@winton
Owner

Hello,

I purposefully left this functionality out, partially to keep things simple, and partially because it seems like you should be restoring the archived record if you really wish to use all of the model's features. Off the top of my head, type columns and polymorphic columns would not behave correctly under the ::Archive class.

Could you provide a scenario where having the full model functionality in the ::Archive class makes more sense than restoring the record and using your original model?

@nielsm

I have an object that is used for building something for a client. Other tables reference that object when activities occur which are billable. The client might choose to delete that original object, & therefore no new actions would be created for it, but if actions have occurred that are billable to that item, I'd like to still reference some criteria of the original object when I generate the bill.

Essentially, I need a way to retrieve all of the Foos (archived or not) when collecting the billable bars. Ideally this would involve some way to pass (:include_archives => true), but I can do a fallback to Foo::Archive.find(id) if Foo.find(id) fails. Once I have each "Foo", I need to grab some perhaps method-scoped values like associations or the name method. Restoring the object isn't appropriate, since I only need it for the billing purpose & don't want the client to suddenly have the Foo's back in their list of manageable items.

@winton
Owner

Ah, I see. Honestly adding this functionality is not a path I want to go down since it does entail a lot of work, and possibly a lot more support questions when certain Rails features do not work as expected. I do have a few suggestions though.

Try doing a Foo.new(Foo::Archive.find(id).attributes) and see if you can use the methods on that object in the way you expect.

If not, consider restoring the record for the brief amount of time that it needs to be used (I'm guessing this is milliseconds in computer land) and then destroy it again when finished. The chance that your client loads the page in this brief span is very unlikely.

Third, consider taking a look at acts_as_paranoid. I made this plugin because we had performance issues with acts_as_paranoid adding the extra SQL on every query, but if you are not under high load, this might be a viable option.

I am going to close this out, but please comment back on what you end up going with.

@nielsm

I completely understand wanting to keep the scope of functionality simple, but figured it was worth asking about.

The Foo.new(Foo::Archive.find(id).attributes)) is an interesting idea. It won't work directly due to the deleted_at column, but it can work like this:

archived_attributes = Foo::Archive.find(id).attributes
archived_attributes.delete("deleted_at")
Foo.new(archived_attributes)

I actually am trying to move away from acts_as_paranoid for many of the same reasons you did & liked the approach you've taken with this project.

@winton
Owner

Ah yes, I forgot about the deleted_at. I'll be sure to remember that if anybody asks about this again. If I have time, this weekend I'll add a method on ::Archive that generates that object automatically.

Yes, acts_as_paranoid gave us a few headaches on the road to scalability. I hope that technique works out for you.

@tpickett66

I know this is an old post but in case anyone still needs this. The way we're getting around this is Foo.new(Foo::Archive.find(id).attributes.reject{|key,val| key.to_s == "deleted_at"})

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.