How to validate unique set of many-to-many associations?












0















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









share|improve this question



























    0















    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









    share|improve this question

























      0












      0








      0








      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









      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 2 at 4:19









      stephennelsonstephennelson

      134




      134
























          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
          });


          }
          });














          draft saved

          draft discarded


















          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
















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Monofisismo

          Angular Downloading a file using contenturl with Basic Authentication

          Olmecas