Hello! I''m trying to figure out how to make two columns unique regardless of order. If order mattered, I could scope the validates_uniqueness_of, like this: http://stackoverflow.com/questions/1633297/how-do-i-validate-two-fields-for-uniqueness But that''s only one way. What if I have two columns, called "sender" and "receiver" and it doesn''t really matter who is the sender and who is the receiver as long as that "grouping" doesn''t exist previously. For example, assume I have this already in the database: Sender = 1, Receiver = 2 Then, the following should occur: Sender = 1, Receiver = 3 # => PASS Sender = 1, Receiver = 2 # => FAIL Sender = 2, Receiver = 1 # => FAIL Sender = 3, Receiver = 1 # => FAIL (if the first one that passed already happened) I tried this: validates_uniqueness_of :sender_id, :scope => :receiver_id validates_uniqueness_of :receiver_id, :scope => :sender_id But that doesn''t quite do it because they aren''t tied together. I can custom-validate this but I was wondering if this pattern has already been accounted for somehow. Any pointers/references? Thanks! -Danimal -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Two ideas: 1. Create two unique database indices, one each for each pairing order and catch the exception on save on create. 2. Do it manually. errors.add(:base, ''already exists'') if (Klass.where(:sender_id => sender.id, :receiver_id => receiver.id) + Klass.where(:sender_id => receiver.id, :receiver_id => sender.id)).any? On Mar 10, 2:09 pm, Danimal <fightonfightw...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hello! > > I''m trying to figure out how to make two columns unique regardless of > order. If order mattered, I could scope the validates_uniqueness_of, > like this:http://stackoverflow.com/questions/1633297/how-do-i-validate-two-fiel... > > But that''s only one way. What if I have two columns, called "sender" > and "receiver" and it doesn''t really matter who is the sender and who > is the receiver as long as that "grouping" doesn''t exist previously. > > For example, assume I have this already in the database: > Sender = 1, Receiver = 2 > > Then, the following should occur: > Sender = 1, Receiver = 3 # => PASS > Sender = 1, Receiver = 2 # => FAIL > Sender = 2, Receiver = 1 # => FAIL > Sender = 3, Receiver = 1 # => FAIL (if the first one that passed > already happened) > > I tried this: > > validates_uniqueness_of :sender_id, :scope => :receiver_id > validates_uniqueness_of :receiver_id, :scope => :sender_id > > But that doesn''t quite do it because they aren''t tied together. I can > custom-validate this but I was wondering if this pattern has already > been accounted for somehow. > > Any pointers/references? > > Thanks! > > -Danimal-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Thanks, Martin! I''ve headed down path #2, but I thought of posting here just in case there already existed a custom validation. Maybe this isn''t a very common thing. Seems to be that usually it''s explicit in the direction (i.e. "husband => wife" relationship or "employer" => "employee" or something like that). -Danimal On Mar 10, 7:26 pm, Martin Streicher <martin.streic...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Two ideas: > > 1. Create two unique database indices, one each for each pairing order > and catch the exception on save on create. > > 2. Do it manually. > > errors.add(:base, ''already exists'') if > (Klass.where(:sender_id => sender.id, :receiver_id => receiver.id) + > Klass.where(:sender_id => receiver.id, :receiver_id => > sender.id)).any? > > On Mar 10, 2:09 pm, Danimal <fightonfightw...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > Hello! > > > I''m trying to figure out how to make two columns unique regardless of > > order. If order mattered, I could scope the validates_uniqueness_of, > > like this:http://stackoverflow.com/questions/1633297/how-do-i-validate-two-fiel... > > > But that''s only one way. What if I have two columns, called "sender" > > and "receiver" and it doesn''t really matter who is the sender and who > > is the receiver as long as that "grouping" doesn''t exist previously. > > > For example, assume I have this already in the database: > > Sender = 1, Receiver = 2 > > > Then, the following should occur: > > Sender = 1, Receiver = 3 # => PASS > > Sender = 1, Receiver = 2 # => FAIL > > Sender = 2, Receiver = 1 # => FAIL > > Sender = 3, Receiver = 1 # => FAIL (if the first one that passed > > already happened) > > > I tried this: > > > validates_uniqueness_of :sender_id, :scope => :receiver_id > > validates_uniqueness_of :receiver_id, :scope => :sender_id > > > But that doesn''t quite do it because they aren''t tied together. I can > > custom-validate this but I was wondering if this pattern has already > > been accounted for somehow. > > > Any pointers/references? > > > Thanks! > > > -Danimal-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Robert Pankowecki (rupert)
2011-Mar-11 10:08 UTC
Re: Validates uniqueness two columns both ways?
You could alway store them in known order so that sender.id <= reciver.id and use scoped validates_uniqueness_of. Assuming that sender and reciver can be exchanged in this relationship and does not have any additional meaning. Like ''friendship'' when it does not matter who is friend A and who is friend B Robert Pankowecki -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Hi Robert! Thanks for the post. Your thought would work, except that it''s very much like ''friendship'' in that it''s immaterial who requested the ''friendship''. And that''s the crux of it. Since Person 1 or Person 2 could be the sender/requester, it has to check both ways. Then again, I just had a thought. Perhaps given two people, the lower ID is always set as the sender and the other as the receiver. Hmmm... then, the order would always be known. If Person 2 requests friendship with Person 1, the friendship object is saved with sender=>1, receiver=>2 Then, if later Person 1 requests friendship with Person 2, it''s saved as sender=>1, receiver=>2 and it would fail validation. Interesting... I need to noodle on that a bit more and see if that would work thoroughly. Thanks! -Danimal On Mar 11, 5:08 am, "Robert Pankowecki (rupert)" <robert.pankowe...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> You could alway store them in known order so that > sender.id <= reciver.id > and use scoped validates_uniqueness_of. > > Assuming that sender and reciver can be exchanged in this relationship > and does not have any additional meaning. > > Like ''friendship'' when it does not matter who is friend A and who is > friend B > > Robert Pankowecki-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Of course, on further thought, The downside to this ID reordering is that I''d lose the data about who did the request. For the ''friendship'', it doesn''t matter. I.e. Person 1 is connected to Person 2 is exactly the same functionally as Person 2 is connected to Person 1 (in my app, that is). But there may be value in knowing which person started the process (i.e. the "sender"). Hmmm... I guess a custom validation it is. -Danimal On Mar 11, 7:38 am, Danimal <fightonfightw...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi Robert! Thanks for the post. > > Your thought would work, except that it''s very much like ''friendship'' > in that it''s immaterial who requested the ''friendship''. And that''s the > crux of it. Since Person 1 or Person 2 could be the sender/requester, > it has to check both ways. > > Then again, I just had a thought. Perhaps given two people, the lower > ID is always set as the sender and the other as the receiver. Hmmm... > then, the order would always be known. > > If Person 2 requests friendship with Person 1, the friendship object > is saved with sender=>1, receiver=>2 > Then, if later Person 1 requests friendship with Person 2, it''s saved > as sender=>1, receiver=>2 and it would fail validation. > > Interesting... I need to noodle on that a bit more and see if that > would work thoroughly. > > Thanks! > > -Danimal > > On Mar 11, 5:08 am, "Robert Pankowecki (rupert)" > > <robert.pankowe...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > You could alway store them in known order so that > > sender.id <= reciver.id > > and use scoped validates_uniqueness_of. > > > Assuming that sender and reciver can be exchanged in this relationship > > and does not have any additional meaning. > > > Like ''friendship'' when it does not matter who is friend A and who is > > friend B > > > Robert Pankowecki-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Robert Pankowecki (rupert)
2011-Mar-12 09:26 UTC
Re: Validates uniqueness two columns both ways?
How about a little trick. Make Id column of the table a string and then: class Friendship < ActiveRecord::Base belongs_to :sender, ... belongs_to :requester, ... before_validation :standarize_id, :on => :create validates_uniqueness_of :id def standarize_id self.id = [sender.id, requester.id].sort.join(",") end end This way we don''t forget the information about whose is the sender and who is requester. Instead we relay on standarized unique id for the the couple. Robert Pankowecki -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.