Hi All, I am new to Ruby and ROR I were trying to create small DSL for conditional validations valid_with_cond :bypass_validation do if self.addresses > 3 errors[:base] << "Can not have more than 3 addresses". end end By this I wanted to create array of method and call them all in custom validation method. this above code I wanted to do attr_accessor :bypass_validation def svalid_cond unless bypass_validation if self.addresses > 3 errors[:base] << "Can not have more than 3 addresses". end end end This way I want in new and edit form I can ask user to click :bypass_validation attribute and I will bypass this validation. I tried to create def valid_with_cond(name, &block) attr_accessor name define_method "svalidator_#{name}" do |*arg| if send name yield *arg end end end But after trying it in Class Person < ActibeRecord::Base valid_with_cond :test do if self.addresses > 3 errors[:base] << "Can not have more than 3 addresses". end end end But when I check it on console Person.test it throw me error test is private method. Anybody could let me know how to correct it. -- Regards, -sharad -- 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.
Frederick Cheung
2011-Jan-08 22:37 UTC
Re: Help How to create DSL for conditional validations
On Jan 8, 10:18 pm, Sharad Pratap <sh4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Class Person < ActibeRecord::Base > valid_with_cond :test do > if self.addresses > 3 > errors[:base] << "Can not have more than 3 addresses". > end > end > end > > But when I check it on console > > Person.test > > it throw me error test is private method. > > Anybody could let me know how to correct it. >Your call to attr_accessor will create instance methods called test and test=, but you tried to call test on the class (and so you end up falling through to Kernel#test). Have you seen that validations take :if and :unless options ? Fred -- 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.
Hi> Your call to attr_accessor will create instance methods called test > and test=, but you tried to call test on the class (and so you end up > falling through to Kernel#test).No I have tested this is not the case, yes I have given wrong example but with object also it is not working, I have given all details below I guess I got it working by hit and trial way, so not sure what exactly is happening around.> Have you seen that validations take :if and :unless options ?I need to use coustom validation, for them I did not see any :if, :unless option But as I got it working I have lot of question in all stages that I want to put else I will never able to know what is happening. test 1: ruby> ruby> def cvalidation(name, &block) ruby> attr_accessor name ruby> define_method "svalidator_#{name}" do |*arg| ruby> if send name ruby> yield *arg ruby> end ruby> end ruby> end => ruby> ruby> class Person ruby> cvalidation :zen do ruby> puts "Yes" ruby> end ruby> end => #<Proc:0x95e73fc@(irb):8 (lambda)> ruby> x = Person.newq NoMethodError: undefined method `newq'' for Person:Class So this is not working now in test 2, I now test only attr_accessor test 2: ruby> def k(name) ruby> attr_accessor name ruby> end => nil ruby> class Personq ruby> k :test ruby> end => nil ruby> x = Personq.new => #<Personq:0x917a4e0> ruby> x.test NoMethodError: private method `test'' called for #<Personq: 0x917a4e0> it again will not work. test 3: ruby> def k(name) ruby> class_eval do ruby> attr_accessor name ruby> end ruby> end => nil ruby> class Pers ruby> k :u ruby> end ruby> x = Pers.new => #<Pers:0x8f9bf0c> ruby> x.u => nil ruby> x.u = "sfdsg" => "sfdsg" ruby> x.u => "sfdsg Q1: Now it is working, but why it did not work in test 2 ? test 4: ruby> def cvalidation(name, &block) ruby> class_eval do ruby> attr_accessor name ruby> define_method "svalidator_#{name}" do |*arg| ruby> if name ruby> yield *arg ruby> end ruby> end ruby> end ruby> end => nil ruby> ruby> class Work ruby> cvalidation :done do ruby> puts "Yes" ruby> end ruby> end => #<Proc:0xa337638@(irb):64 (lambda)> ruby> x = Work.new => #<Work:0xa32d200> ruby> x.svalidator_done Yes => nil ruby> x.done => nil Here define_method is working but it is not using argument `name'' in if condition, it uses some other name method, than provided argument `name'' Q2: Why it is like that and what `name'' method or variable it is actually using in both lines ? ruby> define_method "svalidator_#{name}" do |*arg| ruby> if name test 5: ruby> def cvalidation(name, &block) ruby> class_eval do ruby> attr_accessor name ruby> define_method "svalidator_#{name}" do |*arg| ruby> if send "#{name}" ruby> yield *arg ruby> end ruby> end ruby> end ruby> end => nil ruby> ruby> class QQ ruby> cvalidation :xx do ruby> puts "Yes" ruby> end ruby> end => #<Proc:0xa0aaf28@(irb):105 (lambda)> ruby> x = QQ.new => #<QQ:0xa0a09ec> ruby> x.svalidator_xx => nil ruby> x.xx => nil ruby> x.xx = "sfddsaf" => "sfddsaf" ruby> x.svalidator_xx Yes => nil ruby> x.xx = nil => nil ruby> x.svalidator_xx => nil ruby> class NN ruby> cvalidation :ww do |w| ruby> puts w, " Hi" ruby> end ruby> end => #<Proc:0x9fbe830@(irb):105 (lambda)> ruby> x = NN.new => #<NN:0x9fabb40> ruby> x.ww => nil ruby> x.svalidator_ww => nil ruby> x.ww = "Sharad" => "Sharad" ruby> x.svalidator_ww Hi => nil ruby> x.svalidator_ww "Sharad" Sharad Hi => nil ruby> puts "Sharad", "Hi" Sharad Hi => nil ruby> Here I guess as I see all is working, but I really like to know about `name'' used in ruby> if send "#{name}" in test 5, uses the `name'' arguemnt provided. But ruby> if name in test 4 it do not able to use same `name'' argument Why ? -- Regards, -sharad On Jan 9, 3:37 am, Frederick Cheung <frederick.che...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On Jan 8, 10:18 pm, Sharad Pratap <sh4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > > > Class Person < ActibeRecord::Base > > valid_with_cond :test do > > if self.addresses > 3 > > errors[:base] << "Can not have more than 3 addresses". > > end > > end > > end > > > But when I check it on console > > > Person.test > > > it throw me error test is private method. > > > Anybody could let me know how to correct it. > > Your call to attr_accessor will create instance methods called test > and test=, but you tried to call test on the class (and so you end up > falling through to Kernel#test). > Have you seen that validations take :if and :unless options ? > > Fred-- 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.
Frederick Cheung
2011-Jan-09 14:04 UTC
Re: Help How to create DSL for conditional validations
On Jan 9, 1:22 pm, sharad <sh4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > > Have you seen that validations take :if and :unless options ? > > I need to use coustom validation, for them I did not see any :if, > :unless optionI think you can still do validate :something, :if => :something+else?> > But as I got it working I have lot of question in all stages > that I want to put else I will never able to know what is happening. >[snip> ruby> > ruby> class Person > ruby> cvalidation :zen do > ruby> puts "Yes" > ruby> end > ruby> end > => #<Proc:0x95e73fc@(irb):8 (lambda)> > ruby> x = Person.newq > NoMethodError: undefined method `newq'' for Person:ClassNot sure what this is showing - you haven''t attempted to define newq anywhere> > So this is not working now in test 2, I now test only attr_accessor > > test 2: > > ruby> def k(name) > ruby> attr_accessor name > ruby> end > => nil > ruby> class Personq > ruby> k :test > ruby> end > => nil > ruby> x = Personq.new > => #<Personq:0x917a4e0> > ruby> x.test > NoMethodError: private method `test'' called for #<Personq: > 0x917a4e0> >I ran this in irb and this worked fine.> test 4: > ruby> def cvalidation(name, &block) > ruby> class_eval do > ruby> attr_accessor name > ruby> define_method "svalidator_#{name}" do |*arg| > ruby> if name > ruby> yield *arg > ruby> end > ruby> end > ruby> end > ruby> end > => nil > ruby> > ruby> class Work > ruby> cvalidation :done do > ruby> puts "Yes" > ruby> end > ruby> end > => #<Proc:0xa337638@(irb):64 (lambda)> > ruby> x = Work.new > => #<Work:0xa32d200> > ruby> x.svalidator_done > Yes > => nil > ruby> x.done > => nil > > Here define_method is working but it is not using argument `name'' in > if condition, it uses some other name method, than provided argument > `name'' > > Q2: Why it is like that and what `name'' method or variable it is > actually using in both lines ?blocks are closures, so it sees the same local variables as those that were existent when define_method were called, so it picks up the name that was first argument to cvalidation. self is special though - self will be the value of the object the method is called on.> ruby> define_method "svalidator_#{name}" do |*arg| > ruby> if name > > test 5: > ruby> def cvalidation(name, &block) > ruby> class_eval do > ruby> attr_accessor name > ruby> define_method "svalidator_#{name}" do |*arg| > ruby> if send "#{name}" > ruby> yield *arg > ruby> end > ruby> end > ruby> end > ruby> end > => nil > ruby> > ruby> class QQ > ruby> cvalidation :xx do > ruby> puts "Yes" > ruby> end > ruby> end > => #<Proc:0xa0aaf28@(irb):105 (lambda)> > ruby> x = QQ.new > => #<QQ:0xa0a09ec> > ruby> x.svalidator_xx > => nil > ruby> x.xx > => nil > ruby> x.xx = "sfddsaf" > => "sfddsaf" > ruby> x.svalidator_xx > Yes > => nil > ruby> x.xx = nil > => nil > ruby> x.svalidator_xx > => nil > ruby> class NN > ruby> cvalidation :ww do |w| > ruby> puts w, " Hi" > ruby> end > ruby> end > => #<Proc:0x9fbe830@(irb):105 (lambda)> > ruby> x = NN.new > => #<NN:0x9fabb40> > ruby> x.ww > => nil > ruby> x.svalidator_ww > => nil > ruby> x.ww = "Sharad" > => "Sharad" > ruby> x.svalidator_ww > > Hi > => nil > ruby> x.svalidator_ww "Sharad" > Sharad > Hi > => nil > ruby> puts "Sharad", "Hi" > Sharad > Hi > => nil > ruby> > > Here I guess as I see all is working, but > I really like to know about `name'' used in > > ruby> if send "#{name}" > > in test 5, uses the `name'' arguemnt provided. > > But > ruby> if name > in test 4 it do not able to use same `name'' argument >When you just write name, it picks up the local variable from the closure (it''s ambiguous whether you mean the local variable or the method, and in these cases ruby picks the local variable), but by using send you''re forcing it to call the accessor method. You could also have disambiguated by writing self.name or name() Fred> Why ? > > -- > Regards, > -sharad > > On Jan 9, 3:37 am, Frederick Cheung <frederick.che...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > wrote: > > > > > On Jan 8, 10:18 pm, Sharad Pratap <sh4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > Class Person < ActibeRecord::Base > > > valid_with_cond :test do > > > if self.addresses > 3 > > > errors[:base] << "Can not have more than 3 addresses". > > > end > > > end > > > end > > > > But when I check it on console > > > > Person.test > > > > it throw me error test is private method. > > > > Anybody could let me know how to correct it. > > > Your call to attr_accessor will create instance methods called test > > and test=, but you tried to call test on the class (and so you end up > > falling through to Kernel#test). > > Have you seen that validations take :if and :unless options ? > > > Fred-- 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.
sh4r4d-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2011-Jan-09 18:16 UTC
Re: Help How to create DSL for conditional validations
Hi Frederick!> I think you can still do > validate :something, :if => :something+else?I hope it could be used multiple time with different methods> > ruby> x = Person.newq > > NoMethodError: undefined method `newq'' for Person:Class > > Not sure what this is showing - you haven''t attempted to define newq > anywhereSorry It was my typing mistake.> > test 2: > > .... > I ran this in irb and this worked fine. >But it has not work fine, I again tested it now. my ruby version ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-linux] installed using Ruby Version Manager. For all I got why this is happening. Great thanks for all explanations. -- Regards, -sharad -- 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.