If we have a has_and_belongs_to_many
relationship like this:
class Assembly < ApplicationRecord
has_and_belongs_to_many :parts
end
class Part < ApplicationRecord
has_and_belongs_to_many :assemblies
end
And we use an association to find parts belonging to an Assembly
with id
of 1
like this:
Assembly.find(1).parts
Then is there a way to reference the object that called associated objects - in this case, a way to reference the specific Assembly
from the Part
? Something like this:
Assembly.find(1).parts.each do |part|
the_calling_assembly = part.assembly_that_referenced_me()
end
And, of there is not an builtin way to do this, any suggestions on how to create this behavior?
The best way to achieve this is by using a join model for the join table that is used to implement the many-to-many relation.
So, by now there should be a table, assemblies_parts
You should write a model:
#assemblies_part.rb
class AssemblyPart < ApplicationRecord
belongs_to :assembly
belongs_to :part
end
And you should change your other models too
class Assembly < ApplicationRecord
has_many :assembly_parts
has_many :parts, through: :assembly_parts
end
class Part < ApplicationRecord
has_many :assembly_parts
has_many :assemblies, through: :assembly_parts
end
So, you could now do;
Assembly.find(1).assembly_parts.each do |assembly_part|
assembly = assembly_part.assembly
part = assembly_part.part
end
If you would like to persist the assembly to the part, throughout the process, you could do the following (caution: this does not persist to the DB)
class Part < ApplicationRecord
#...
attr_accessor :assembly
end
And do this next:
Assembly.find(1).assembly_parts.each do |assembly_part|
part = assembly_part.part
part.assembly = assembly_part.assembly #only valid through the current process
end
By using the attr_accessor
you can also do this without the join model n implementation.
No new migrations are required for the above solution. Minor typos or syntax errors might exist because I'm doing this on a phone screen. I hope it helps, anyhow.
this is just an idea
If you go to http://api.rubyonrails.org/ and select Active Record/Associations
you will see that there are 2 classes
but also you can see al the classes and modules for the Association
, but I believe you should patch the Collection Proxies
class
so you create the class in lib/core_ext/active_record/associations/collection_proxy.rb
and you create an initializer to required
at your server startup.
if this is what you want to achieve
Assembly.find(1).parts.each do |part|
the_calling_assembly = part.assembly_that_referenced_me()
end
you can just create a method
that does it. It is a good idea to check the CollectionProxy
class on github
module ActiveRecord
module Associations
class CollectionProxy < Relation
def parent_instance
Assembly.find(self.assembly_id)
end
end
end
end
so this is not a complete answer and probably I did not realize the complexity of your functionalities, but I suggest you to decrease the complexity.
Also understand what is the class
from assembly_part
, because that is the one you need to patch. ( assembly_part.class
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.