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

Support polymorphic belongs to #389

Closed
josevalim opened this issue Jan 23, 2015 · 15 comments
Closed

Support polymorphic belongs to #389

josevalim opened this issue Jan 23, 2015 · 15 comments

Comments

@josevalim
Copy link
Member

No description provided.

@losvedir
Copy link

For what it's worth, I think this is a misfeature. My company's rails app has used polymorphic associations in the past, but we're now outlawing it since it's not compatible with true Foreign Key support, which we feel is much more important and Rails can now handle. We were encouraged into the polymorphic approach because of Rails, but now regret it.

@josevalim
Copy link
Member Author

@losvedir thanks for the feedback.

Indeed, one of the plans for this feature is to actually research it is really needed. That said, I would love to hear more about your alternatives to polymorphic belongs to. How have you solved this issue? Multiple tables?

@MSch
Copy link
Contributor

MSch commented Feb 20, 2015

My 0.02 EUR:

A column that's NULL takes up 1 bit. A text column storing the table name takes up 1 byte plus the actual string. A enum column takes up 4 bytes. So as long as the polymorphic relationship is to less than 32 tables going with NULLable columns is just the smart thing to do.

@losvedir
Copy link

@josevalim - Yes, separate models, multiple tables. We figured if we wanted a consistent interface for both, we'd write some sort of plain old ruby object decorator over them, or have each import a shared module. But we haven't had to yet, so that's still just a hypothetical.

The motivating reason for our policy is true foreign key support, which as far as I know is not easily possible in postgres (our DB) with polymorphic ID/type columns. We're trying to push as much validation support as we can into the DB layer (null: true, default values, foreign keys, etc). The upshot is that it allows us to explore other technologies (e.g. Elixir/Phoenix!) to run atop the database.

That said, this was a recent change, and we haven't gone back to change our polymorphic associations, so I don't know how well the multiple tables will work out in all our use cases. It looks a little hairy to do, but then that's why I'm frustrated rails encouraged us to do that in the first place!

@josevalim
Copy link
Member Author

@MSch not sure I understood it. Do you propose multiple columns instead of polymorphic belongs to?

@briksoftware
Copy link
Contributor

I am with @MSch on this, one can use multiple columns (A_ID, B_ID, etc) which would allow setting foreign key constrains. With PostgreSQL and probably MySQL you also have "check" constraints so it should be possible to enforce that only one of those fields can be non-null at any given time and even that at least one of them is non-null.

However, the framework could hide this behind a polymorphic belongs_to in the form of

belongs_to :superEntity, through: [{EntityA, :a_id}, {EntityB, :b_id}]

where only one of the id columns is non-NULL at any given time.

admittedly it could require quite a lot of code and stored metadata to handle this but it would still be quite feasible. The "classic" implementation of polymorphic association is easier but as @losvedir mentioned it lacks support from the backend.

@josevalim
Copy link
Member Author

Thanks everyone for the feedback, very insightful.

@briksoftware I think this is a great idea. We could allow a model to be used with different sources. This would allow us to map one model and multiple tables easily. Something like:

User
  has_many :emails, Email, source: "user_emails"

I am closing this and opening an issue to allow configurable source/model pairs.

@peck
Copy link

peck commented Mar 17, 2015

linking to the new issue as I had a tough time tracking it down with search #478

@egilburg
Copy link

@josevalim any chance for this to be reconsidered?

I'm designing a reporting database which would not be a source of truth for data (and data therein would be subject to refresh from source), and as such referential integrity is less of an issue than in a production source-of-truth database, as it's supposed to just accept 3rd party schemas as source of truth for reporting purposes only.

Furthermore, I'm looking towards being able to import data to it from existing production (Rails) systems which already heavily use polymorphic tables for common joins like "tags" or "comments", and would rather not have to map an existing polymorphic join to and from many tables during import/export ETL process.

(as a more extreme case I even asked whether its feasible to drive associations from jsonb values, as discussed in https://groups.google.com/forum/#!topic/elixir-ecto/TPvF7Xxow7g )

I could also give a shot towards writing a Phoenix extension to support this (for lack of me knowing a proper term equivalent to "Rails gem" :) - is there any content or manual or style on writing 3rd party extensions to Phoenix?

Thanks!

@josevalim
Copy link
Member Author

There are no plans for reconsidering this. Using polymorphic associations is a really bad practice, for both relation and nosql databases, which we don't want to promote. To create a Phoenix 3rd party extension, you just create a package like any other, except it would have a dependency on Phoenix.

@izelnakri
Copy link

I understand the performance benefits of using the two approaches mentioned here: http://hexdocs.pm/ecto/Ecto.Schema.html (search: Polymorphic associations). However I believe this actually makes the implementation and code less developer friendly:

Every time a new model needs polymorphic association, new column(first example) or table(second example) has to be created.
Additionally, the query syntax is more verbose and complicated thus less productive this way but that is my personal opinion.

@smithaitufe
Copy link

Please I am trying to get polymorphic association work. I want to implement this

Address <-> User
User can have billing_addresses and shipping_addresses

Following the docs, I am completely lost.
I have generated a create migration and model for Address table containing the fields
(address1, address2, city, state_id, country_id, address_type_id)

Next I have User model which have the following relationships
has_many :billing_addresses
has_many :shipping_addresses

I intend to store both billing_addresses and shipping_addresses in the Address table

I also have Shop which will have the
has_one :addresses, Address

Please can someone tell me how to do this in ecto

@jbhatab
Copy link

jbhatab commented Aug 29, 2016

@josevalim Will it ever be possible to go the route @briksoftware mentioned of defining multiple columns that the belongs to works for? The code I'm looking at right now to replicate rails 'public_activity' gem, https://github.com/chaps-io/public_activity, is looking pretty rugged no matter which way I spin this.

Any advice on something like this because I don't see a clean path with the current tools provided.

@josevalim
Copy link
Member Author

We support multiple sources in Ecto:

belongs_to :manager, {"post_managers", PostManager}

I believe the docs were updates with this example. If not, a PR is welcome!

On Monday, August 29, 2016, Blaine Hatab notifications@github.com wrote:

@josevalim https://github.com/josevalim Will it ever be possible to go
the route @briksoftware https://github.com/briksoftware mentioned of
defining multiple columns that the belongs to works for? The code I'm
looking at right now to replicate rails 'public_activity' gem,
https://github.com/chaps-io/public_activity, is looking pretty rugged no
matter which way I spin this.

Any advice on something like this because I don't see a clean path with
the current tools provided.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#389 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAlbmT_OFa_8FIE_B9FBnIac1UB6LTTks5qk2ZegaJpZM4DWTct
.

José Valimwww.plataformatec.com.br
http://www.plataformatec.com.br/Founder and Director of R&D

@kidbombay
Copy link

@jbhatab did you ever get anywhere with recreating public activity for Elixir? I'm in the same boat.

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

No branches or pull requests

10 participants