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

has_one does not always allow a unique constraint #35

Open
adsteel opened this issue Jun 3, 2016 · 7 comments
Open

has_one does not always allow a unique constraint #35

adsteel opened this issue Jun 3, 2016 · 7 comments

Comments

@adsteel
Copy link

adsteel commented Jun 3, 2016

A has_one may be a refinement of a has_many. In this case, there cannot and should not be a unique constraint on the foreign key. Currently the gem does not distinguish.

class Blog
  has_many :posts
  has_one :most_recent_post, -> { order(published_at: :desc) }, class_name: 'Post'
  ...
end
@adsteel
Copy link
Author

adsteel commented Jun 9, 2016

This could potentially be addressed by getting the class of each has_one and checking: If that class has a has_many relationship as well then it would disqualify it for a unique constraint. Association reflections would be useful here:

@trptcolin
Copy link
Owner

Yep, totally, makes sense.

I'm kind of wondering about similar use cases, but slightly different implementations too. When I've done this kind of thing in the past, I've used an instance method, rather than a has_one, to implement things like #most_recent_post (this has the side benefit that I don't have to worry about accidental deletion if someone uses the generated setter). If someone went in the other direction, and implemented #posts as an instance method, and left the has_one as an association, we wouldn't be able to spot it with this strategy.

That's the only concrete case I've got in mind right now, but my gut says that if there's this one use case that we've missed up until this point, there might be others as well that I'm not thinking of (which makes me just want to give users an escape hatch).

@adsteel
Copy link
Author

adsteel commented Jun 9, 2016

That's a good point. An escape hatch is making more sense.

@jobertabma
Copy link

@trptcolin @adsteel Bumping this old issue! We recently ran into this with two separate models that were both referencing a polymorphic field, one with has_one, the other with has_many. We were able to work around this by defining a getter on the model for the has_one relationship.

For the escape hatch: are you thinking an additional option set on the has_one relationship / uniqueness validation? Using a comment will be hard since the gem relies on an introspection class instead of a full-blown parser. Something like:

class SomeModel
  has_one :something, disable_consistency_fail_unique_constraint_check: true
  # or
  validates :something_else, uniqueness: true, disable_consistency_fail_unique_constraint_check: true
end

@trptcolin
Copy link
Owner

I was thinking more like a config file passed to consistency_fail where you can say “ignore this association; I know about it already.” I’d rather not require users to decorate production code with knowledge of this specific tool.

@louietyj
Copy link

louietyj commented Oct 3, 2018

Hey @trptcolin is there a solution to this (if there's a config file it doesn't seem documented anywhere)? We have a very similar use case where a has_one association is a scoped version of a has_many association. Redefining the has_one association as an instance method is not appropriate for us because we join through this association a lot, e.g. most of the time we impose an ordering based on an attribute on the association.

@trptcolin
Copy link
Owner

trptcolin commented Oct 3, 2018

@louietyj hasn't been implemented yet, but I'd love a PR for it!

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

4 participants