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

[RFC] Consider multiple archive numbers for association records #15

Open
janxious opened this issue Mar 14, 2016 · 0 comments
Open

[RFC] Consider multiple archive numbers for association records #15

janxious opened this issue Mar 14, 2016 · 0 comments

Comments

@janxious
Copy link
Contributor

@esquivalient @stevegrossi

This came up as a "I expected this to work!" kinda thing, and am curious about your opinion on the matter.

A long explanation of the issue

# example adapted from http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many
class Assembly < ActiveRecord::Base
  acts_as_archival
  has_many :manifests, dependent: :destroy
  has_many :parts, through: :manifests, dependent: :destroy
end

class Manifest < ActiveRecord::Base
  acts_as_archival
  belongs_to :assembly
  belongs_to :part
end

class Part < ActiveRecord::Base
  acts_as_archival
  has_many :manifests, dependent: :destroy
  has_many :assemblies, through: :manifests, dependent: :destroy
end

In this situation, Assembly and Part can be archived separately, and either will correctly archive the Manifest connecting them. But that doesn't represent the ideal for a situation in which a Part is archived after a Manifest connected to it is archived, since they will have different archive_numbers. Here is some demonstrative code:

assembly = Assembly.create
part = Part.create
manifest = Manifest.create(assembly: assembly, part: part)

assembly.archive
assembly.archived? # => true
manifest.archived? # => true
part.archive
part.archived? # => true
part.archive_number == manifest.archive_number # => false # starting to see a problem!

assembly.unarchive
manifest.archived? # => false
part.archived? # => true

manifest.unarchived.joins(:parts) # => [manifest] # oops!

So, this will now return a set of Manifests that includes an archived Part, which is technically correct but perhaps logically incorrect.

Solution

A thing that comes to mind: change the schema to allow multiple archive_number columns.

manifests:
  archive_number_part: string
  archive_number_assembly: string

Which would allow us to do something that is effectively:

class Manifest
  def archived?
    [archive_number, archive_number_part, archive_number_assembly].any?(&:present?)
  end
end

class Assembly
  def archive
    archive_number = generate_archive_number
    self.archive_number = archive_number
    manifests.each do |manifest|
      manifest.update_attributes(archive_number_assembly: archive_number)
    end
    save
  end
end

Note the actual code is going to be a lot more meta, but this is effectively a way to achieve this, and “easily” extends to 3+-way associations.


Another thing to consider is surfacing (through documentation) the internals of the archiving modules so that they can be derived from more easily to make custom archived? statuses easier to achieve. I don't know if that's a good idea, but certainly in non-trivial situations there is not much guidance in the repo itself for how to deal with multi-way conditional archiving - and may be it should remain that way. I htink explaining the philosophy behind this tool further might help, though. This is a solution to 90%+ of archiving problems, but the other 10% is murky. It's important to know that your application can override any of our internal bits to work within the application. Like ARec itself, this is often not needed, but ARec does a reasonable job of being like "it's okay. sometimes we aren't perfect and you need to use raw sql or do some transactions in a service or whatever" #Rambles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant