How to validate unique set of many-to-many associations?
I want to validate that the set of associations for an instance are unique to all other instances, and if it is not unique I want it to be invalid.
In this case, I am working with a many_to_many relationship, so, an Exercise has many elements, and elements can have many Exercises. So I would like each exercise to have a unique set of elements so an exercise can have as many element associations as possible, but never have the same combination of elements as another exercise.
I've tried adding a custom validation to the join model but that doesn't work when I submit a lot of revised associations at one time (such as when I am editing associations through a nested form)
I've also tried putting the validation in the Exercise model by comparing the associations of the created or updated exercise against all other exercise element association sets that exist, but that doesn't seem to work because the associations aren't created until after I need to validate them. So it seems I need the associations built in order to validate their uniqueness, but once they're built it's already too late.
class Exercise < ApplicationRecord
has_many :exercise_elements, dependent: :destroy
has_many :elements, through: :exercise_elements
accepts_nested_attributes_for :exercise_elements, allow_destroy: true
validate :element_uniqueness, if: :elements_unique?, on: :update
def elements_unique?
all_exercises_but_self = Exercise.where.not(id: self.id)
all_exercises = all_exercises_but_self.map(&:elements)
all_sorted = all_exercises.each.sort
this_exercise = self.elements.sort
all_sorted.include?(this_exercise) ? true : false
end
def element_uniqueness
if elements_unique?
self.errors[:base] << "Exercise already exists, consider adding
different elements"
end
end
end
class ExerciseElement < ApplicationRecord
belongs_to :exercise
belongs_to :element
end
class Element < ApplicationRecord
belongs_to :element_category
has_many :exercise_elements
has_many :exercises, through: :exercise_elements
end
I would expect
exercise1 = Exercise.create
exercise1.elements.push([Element.find(1), Element.find(2)])
exercise1.valid? > true
exercise2 = Exercise.create
exercise2.elements << Element.find(2)
exercise2.valid? > true
exercise2.elements << Element.find(1)
exercise2.valid? > false # invalid because associated elements are not a
# unique set
# because exercise2.elements == exercise1.elements
ruby-on-rails validation many-to-many associations
add a comment |
I want to validate that the set of associations for an instance are unique to all other instances, and if it is not unique I want it to be invalid.
In this case, I am working with a many_to_many relationship, so, an Exercise has many elements, and elements can have many Exercises. So I would like each exercise to have a unique set of elements so an exercise can have as many element associations as possible, but never have the same combination of elements as another exercise.
I've tried adding a custom validation to the join model but that doesn't work when I submit a lot of revised associations at one time (such as when I am editing associations through a nested form)
I've also tried putting the validation in the Exercise model by comparing the associations of the created or updated exercise against all other exercise element association sets that exist, but that doesn't seem to work because the associations aren't created until after I need to validate them. So it seems I need the associations built in order to validate their uniqueness, but once they're built it's already too late.
class Exercise < ApplicationRecord
has_many :exercise_elements, dependent: :destroy
has_many :elements, through: :exercise_elements
accepts_nested_attributes_for :exercise_elements, allow_destroy: true
validate :element_uniqueness, if: :elements_unique?, on: :update
def elements_unique?
all_exercises_but_self = Exercise.where.not(id: self.id)
all_exercises = all_exercises_but_self.map(&:elements)
all_sorted = all_exercises.each.sort
this_exercise = self.elements.sort
all_sorted.include?(this_exercise) ? true : false
end
def element_uniqueness
if elements_unique?
self.errors[:base] << "Exercise already exists, consider adding
different elements"
end
end
end
class ExerciseElement < ApplicationRecord
belongs_to :exercise
belongs_to :element
end
class Element < ApplicationRecord
belongs_to :element_category
has_many :exercise_elements
has_many :exercises, through: :exercise_elements
end
I would expect
exercise1 = Exercise.create
exercise1.elements.push([Element.find(1), Element.find(2)])
exercise1.valid? > true
exercise2 = Exercise.create
exercise2.elements << Element.find(2)
exercise2.valid? > true
exercise2.elements << Element.find(1)
exercise2.valid? > false # invalid because associated elements are not a
# unique set
# because exercise2.elements == exercise1.elements
ruby-on-rails validation many-to-many associations
add a comment |
I want to validate that the set of associations for an instance are unique to all other instances, and if it is not unique I want it to be invalid.
In this case, I am working with a many_to_many relationship, so, an Exercise has many elements, and elements can have many Exercises. So I would like each exercise to have a unique set of elements so an exercise can have as many element associations as possible, but never have the same combination of elements as another exercise.
I've tried adding a custom validation to the join model but that doesn't work when I submit a lot of revised associations at one time (such as when I am editing associations through a nested form)
I've also tried putting the validation in the Exercise model by comparing the associations of the created or updated exercise against all other exercise element association sets that exist, but that doesn't seem to work because the associations aren't created until after I need to validate them. So it seems I need the associations built in order to validate their uniqueness, but once they're built it's already too late.
class Exercise < ApplicationRecord
has_many :exercise_elements, dependent: :destroy
has_many :elements, through: :exercise_elements
accepts_nested_attributes_for :exercise_elements, allow_destroy: true
validate :element_uniqueness, if: :elements_unique?, on: :update
def elements_unique?
all_exercises_but_self = Exercise.where.not(id: self.id)
all_exercises = all_exercises_but_self.map(&:elements)
all_sorted = all_exercises.each.sort
this_exercise = self.elements.sort
all_sorted.include?(this_exercise) ? true : false
end
def element_uniqueness
if elements_unique?
self.errors[:base] << "Exercise already exists, consider adding
different elements"
end
end
end
class ExerciseElement < ApplicationRecord
belongs_to :exercise
belongs_to :element
end
class Element < ApplicationRecord
belongs_to :element_category
has_many :exercise_elements
has_many :exercises, through: :exercise_elements
end
I would expect
exercise1 = Exercise.create
exercise1.elements.push([Element.find(1), Element.find(2)])
exercise1.valid? > true
exercise2 = Exercise.create
exercise2.elements << Element.find(2)
exercise2.valid? > true
exercise2.elements << Element.find(1)
exercise2.valid? > false # invalid because associated elements are not a
# unique set
# because exercise2.elements == exercise1.elements
ruby-on-rails validation many-to-many associations
I want to validate that the set of associations for an instance are unique to all other instances, and if it is not unique I want it to be invalid.
In this case, I am working with a many_to_many relationship, so, an Exercise has many elements, and elements can have many Exercises. So I would like each exercise to have a unique set of elements so an exercise can have as many element associations as possible, but never have the same combination of elements as another exercise.
I've tried adding a custom validation to the join model but that doesn't work when I submit a lot of revised associations at one time (such as when I am editing associations through a nested form)
I've also tried putting the validation in the Exercise model by comparing the associations of the created or updated exercise against all other exercise element association sets that exist, but that doesn't seem to work because the associations aren't created until after I need to validate them. So it seems I need the associations built in order to validate their uniqueness, but once they're built it's already too late.
class Exercise < ApplicationRecord
has_many :exercise_elements, dependent: :destroy
has_many :elements, through: :exercise_elements
accepts_nested_attributes_for :exercise_elements, allow_destroy: true
validate :element_uniqueness, if: :elements_unique?, on: :update
def elements_unique?
all_exercises_but_self = Exercise.where.not(id: self.id)
all_exercises = all_exercises_but_self.map(&:elements)
all_sorted = all_exercises.each.sort
this_exercise = self.elements.sort
all_sorted.include?(this_exercise) ? true : false
end
def element_uniqueness
if elements_unique?
self.errors[:base] << "Exercise already exists, consider adding
different elements"
end
end
end
class ExerciseElement < ApplicationRecord
belongs_to :exercise
belongs_to :element
end
class Element < ApplicationRecord
belongs_to :element_category
has_many :exercise_elements
has_many :exercises, through: :exercise_elements
end
I would expect
exercise1 = Exercise.create
exercise1.elements.push([Element.find(1), Element.find(2)])
exercise1.valid? > true
exercise2 = Exercise.create
exercise2.elements << Element.find(2)
exercise2.valid? > true
exercise2.elements << Element.find(1)
exercise2.valid? > false # invalid because associated elements are not a
# unique set
# because exercise2.elements == exercise1.elements
ruby-on-rails validation many-to-many associations
ruby-on-rails validation many-to-many associations
asked Jan 2 at 4:19
stephennelsonstephennelson
134
134
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54001144%2fhow-to-validate-unique-set-of-many-to-many-associations%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54001144%2fhow-to-validate-unique-set-of-many-to-many-associations%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown