I have some class with this set :
class Campaign < ActiveRecord::Base
belongs_to :user
validates_presence_of :title, :description
def initialize
validates_format_of_many([:title, :description])
end
def validates_format_of_many(inputs)
if (!inputs.nil?)
inputs.each do |input|
validates_format_of input => /^[.]/, :allow_nil => false, :allow_blank => false
puts YAML::dump('test1')
end
else
puts YAML::dump('test2')
end
end
end
The problem is that I get some error message undefined methodinclude?' for nil:NilClass`
and in the stack
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.14/lib/active_record/attribute_methods.rb:257:in `method_missing'
/var/www/gitorious/app/models/campaign.rb:13:in `validates_format_of_many'
/var/www/gitorious/app/models/campaign.rb:12:in `each'
/var/www/gitorious/app/models/campaign.rb:12:in `validates_format_of_many'
/var/www/gitorious/app/models/campaign.rb:7:in `initialize'
/var/www/gitorious/app/controllers/campaigns_controller.rb:28:in `new'
/var/www/gitorious/app/controllers/campaigns_controller.rb:28:in `new'
Firstly if you overwrite initialize, you should call super, this will allow the super_class to perform its initialization tasks
def initialize
validates_format_of_many([:title, :description])
super
end
But it is recommended for AR to use callbacks. Check http://guides.rubyonrails.org/active_record_validations_callbacks.html
Example:
class Campaign < ActiveRecord::Base
belongs_to :user
validates_presence_of :title, :description
after_initialize { validates_format_of_many([:title, :description]) }
def validates_format_of_many(inputs)
if (!inputs.nil?)
inputs.each do |input|
validates_format_of input => /^[.]/, :allow_nil => false, :allow_blank => false
puts YAML::dump('test1')
end
else
puts YAML::dump('test2')
end
end
end
But be careful cause your validates_format_of_many will be called for Campaign.new when creating a new record, and also for Campaign.find ... when loading records from the database
Related
Below is error and the spec listed for my failing test , not sure why it keep getting failed with following message even though I see the method getting invoked on #user.save
Failure/Error: expect(#performer).should_receive(:store_performer)
(#<RSpec::Expectations::ExpectationTarget:0x007f9ec42b5808>).store_performer(any args)
expected: 1 time
received: 0 times
Once again
if I comment the should_receive I do see the method getting invoked (confirmed by virtue of puts) on #user.save call (During that I also examine the object_id of #performer inside the spec and inside the invoked method and found them to be same)
Note: Basically the store_performer , update_minimum_payout and update_to_be_paid are after_save callback
FYI the test case
it 'should invoke callback method' do
new_single_performer
#performer = #user.performer
expect(#performer).should_receive(:store_performer)
expect(#performer).should_receive(:update_minimum_payout)
expect(#performer).should_receive(:update_to_be_paid)
#user.save
end
User.rb
class User < ActiveRecord::Base
# Activity Log (formerly called User Activity)
cattr_accessor :current_user
has_one :performer,
:dependent => :destroy, :validate => true,:inverse_of => :user,:include => :profile # auto load the profile
## Some more association
scope :performers, where(:is_performer => true)
scope :active, where(:active => true)
## Some more scope
## Validation
validates_presence_of :first_name, :last_name, :email #, :password, :password_confirmation
validates_presence_of :site_id, :unless => :is_referrer?
validates_format_of :first_name, :message => "Characters not allowed: $\##!^&*(){}", :with => /^[\w\s]+z/
validates_format_of :last_name, :message => "Characters not allowed: $\##!^&*(){}", :with => /^[\w\s]+z/
validates_format_of :email, :message => "Invalid Email address", :with => /[\w\.\-\#]+z/
before_save :geocode, :if => :should_change_geocode?
before_save :check_role
after_create :update_vendor_id
after_create :notify_admin
after_save :store_changes,:if => :if_changed?
after_save :setup_account,:if => :studio_active_changed?
after_save :approval_notification,:if => :send_notification_present?
end
Performer.rb
class Performer < ActiveRecord::Base
belongs_to :user, :conditions => {:is_performer => true},:inverse_of => :performer
# validations
validates :date_of_birth, :address_1, :city, :state, :zipcode, :country, :phone_number,
after_save :store_performer
after_destroy :destroy_performer_source
after_save :update_minimum_payout ,:if => :minimum_payout_changed?
after_save :update_to_be_paid ,:if => :include_in_payouts_changed?
private
def store_performer
## Performer Source is Mongo document
performer_source = PerformerSource.find_or_create_by(:performer_id => self.id)
performer_source.update_attributes(performer_hash)
performer_source
end
def update_minimum_payout
self.current_payout.update_attributes(:minimum_payout => self.minimum_payout)
end
def update_to_be_paid
self.current_payout.update_attributes(:to_be_paid => self.include_in_payouts)
end
end
PerformerSource
class PerformerSource
include Mongoid::Document
end
JFI my Rspec Version is 2.12.2
I have the following model:
class Article < ActiveRecord::Base
attr_accessible :body, :date_time, :excerpt, :permalink, :title, :premium, :status
before_create :set_defaults
validates_inclusion_of :status , :in => %w(draft pending published) , :allow_blank => false
def set_defaults
self.status ||= 'draft'
end
end
However when I go to create one like this:
article = Article.new( {
"title" => "test",
"body" => "test" ,
"excerpt" => "test"
} )
article.save
It fails and provides the error:
[:status, "is not included in the list"]
I'm trying to figure out why a default is not being set. Any ideas?
I think you want before_validation :set_defaults , :on => :create, validations run and then before create callbacks.
Is it possible to use the roles used for attr_accessible and attr_protected? I'm trying to setup a validation that only executes when not an admin (like this sort of http://launchware.com/articles/whats-new-in-edge-scoped-mass-assignment-in-rails-3-1). For example:
class User < ActiveRecord::Base
def validate(record)
unless # role.admin?
record.errors[:name] << 'Wrong length' if ...
end
end
end
user = User.create({ ... }, role: "admin")
After looking into this and digging through the source code, it appears that the role passed in when creating an Active Record object is exposed through a protected method mass_assignment_role. Thus, the code in question can be re-written as:
class User < ActiveRecord::Base
def validate(record)
unless mass_assignment_role.eql? :admin
record.errors[:name] << 'Wrong length' if ...
end
end
end
user = User.create({ ... }, role: "admin")
Sure can would be something like this:
class User < ActiveRecord::Base
attr_accessible :role
validates :record_validation
def record_validation
unless self.role == "admin"
errors.add(:name, "error message") if ..
end
end
You could do this
class User < ActiveRecord::Base
with_options :if => :is_admin? do |admin|
admin.validates :password, :length => { :minimum => 10 } #sample validations
admin.validates :email, :presence => true #sample validations
end
end
5.4 Grouping conditional validations
A model Country has a attribute code which is automatically converted to lowercase by a before_save callback. Is it possible to force this behaviour on "magic" methods without rewriting large chunks of ActiveRecord::Base?
class Country < ActiveRecord::Base
attr_accessible :code
validates :code, :presence => true
validates_uniqueness_of :code, :case_sensitive => false
before_save do |country|
country.code.downcase! unless country.code.nil?
end
end
RSpec
describe Country do
describe 'data normalization'
before :each do
#country = FactoryGirl.create(:country, :code => 'DE')
end
# passes
it 'should normalize the code to lowercase on insert' do
#country.code.should eq 'de'
end
# fails
it 'should be agnostic to uppercase finds' do
country = Country.find_by_code('DE')
country.should_not be_nil
end
# fails
it 'should be agnostic to uppercase finds_or_creates' do
country = Country.find_or_create_by_code('DE')
country.id.should_not be_nil # ActiveRecord Bug?
end
end
This is what I came up with, altough I really hate that approach (as mentioned in the question). An easy alternative would be to set the column, table or whole database up to ignore case (but this is db dependendt).
class Country < ActiveRecord::Base
attr_accessible :code
validates :code, :presence => true
validates_uniqueness_of :code, :case_sensitive => false
before_save do |country|
country.code.downcase! unless country.code.nil?
end
class ActiveRecord::Base
def self.method_missing_with_code_finders(method_id, *arguments, &block)
if match = (ActiveRecord::DynamicFinderMatch.match(method_id) || ActiveRecord::DynamicScopeMatch.match(method_id))
attribute_names = match.attribute_names
if code_index = attribute_names.find_index('code')
arguments[code_index].downcase!
end
end
method_missing_without_code_finders(method_id, *arguments, &block)
end
class << self
alias_method_chain(:method_missing, :code_finders)
end
end
end
I'm totally blocked on this.
See this code:
# user.rb
class User < ActiveRecord::Base
has_one :address
accepts_nested_attributes_for :address
validates_associated :address, :if => Proc.new {|u| u.addressable? }
end
# address.rb
class Address < ActiveRecord::Base
belongs_to :user
validates_presence_of :address_text
end
# user_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class UserTest < ActiveSupport::TestCase
setup { }
test "address validation is not ran w update attributes and anaf" do
#user = User.create!
#user.build_address
assert_nothing_raised do
#user.update_attributes!(:addressable => false, :address_attributes => {:address => "test"})
end
end
test "address validation w update_attributes and anaf" do
#user = User.create!
#user.build_address
#user.save
assert_raise ActiveRecord::RecordInvalid do
#user.update_attributes!(:addressable => true, :address_attributes => {:address => "test"})
end
end
end
The first test will fail.
The user model validates an associated address model, but is only supposed to do it if a flag is true. In practice it does it all the time.
What is going on?
Actually I ran into further problems with my (more complicated) real world scenario that were only solved by doing the equivalent of:
def validate_associated_records_for_address
self.addressable? ? validate_single_association(User.reflect_on_association(:address)) : nil
end
This adapts anaf's compulsory validations to only run under the condition we want (addressable? is true).
The validates_associated...:if is not necessary now.