I’m trying to create a polymorphic relation between three tables. I’m confused about some of the things and how to do it properly.
So I’m following Solidus e-commerce which is written in Ruby. I have got two tables which have Zone and Zone_Member.
with_options through: :zone_members, source: :zoneable do
has_many :countries, source_type: "Spree::Country"
has_many :states, source_type: "Spree::State"
belongs_to :zone, class_name: 'Spree::Zone', counter_cache: true, inverse_of: :zone_members, optional: true
belongs_to :zoneable, polymorphic: true, optional: true
Can I create a Zoneable table where I can store country id and state id? But I’m confused about the relation
Or is there any other way to do this?
Yes, there is another way to do it…
But it’s not how rails does it, it’s different
I got a different way
field :zoneable_type, :string
field :zoneable_id, :integer
belongs_to :zone, Zone
the zoneable_type can be the Module name of the zone type
Elixir.Country or Elixir.State
and the zoneable_id is its id
as an example the Repo.get/2 can call this way
iex> type= zone_member.zoneable_type|>to_atom
zone= Repo.get(type, zone_member.zoneable_id)
Well, You can but it is not recommended
First of all, it is important to remember Ecto does not provide the same type of polymorphic associations available in frameworks such as Rails and Laravel. In such frameworks, a polymorphic association uses two columns, the parent_id and parent_type. For example, one todo item would have parent_id of 1 with parent_type of “TodoList” while another would have parent_id of 1 with parent_type of “Project”.
The issue with the design above is that it breaks database references. The database is no longer capable of guaranteeing the item you associate to exists or will continue to exist in the future. This leads to an inconsistent database which end-up pushing workarounds to your application.
The design above is also extremely inefficient, especially if you’re working with large tables. Bear in mind that if that’s your case, you might be forced to remove such polymorphic references in the future when frequent polymorphic queries start grinding the database to a halt even after adding indexes and optimizing the database.
Check also the
polymorphic_embed library out, which may address some of those polymorphic associations needs.
What about Ecto.Type? We can store the same module as a string but when we fetch it can give the module. Then we can do all the things with that.