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
Related
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.
I get this error
ActiveModel::MassAssignmentSecurity::Error in SessionsController#create
Can't mass-assign protected attributes: created_at, updated_at
I think I can add some codes to solve this problem.
class User < ActiveRecord::Base
attr_accessible :email, :nickname, :authentications_attributes, :created_at, :updated_at
Why Omniauth changes the created_at and updated_at?
In addition to add "attr_accessible :created_at, :updated_at", there are other ways?
This is my models/user.rb
class User < ActiveRecord::Base
attr_accessible :email, :nickname, :authentications_attributes, :created_at, :updated_at
validates :nickname, :presence => true
validates :email, :presence => true, :uniqueness => true
has_many :authentications
accepts_nested_attributes_for :authentications
class << self
def from_auth(auth)
Authentication.find_by_provider_and_uid(auth[:provider],
auth[:uid]).try(:user) ||
create!(
:nickname => auth[:info][:nickname],
:email => auth[:info][:email],
:authentications_attributes => [
Authentication.new(:provider => auth[:provider],
:uid => auth[:uid]
).attributes
])
end
end
end
This is my models/identity.rb
class Identity < OmniAuth::Identity::Models::ActiveRecord
attr_accessible :nickname, :email, :password, :password_confirmation, :authentications_attributes
validates_presence_of :nickname, :email
validates_uniqueness_of :nickname, :email
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
end
This is my models/authentication.rb
class Authentication < ActiveRecord::Base
attr_accessible :user_id, :provider, :uid, :authentications_attributes, :created_at, :updated_at
validates :provider, :presence => true, :uniqueness => {:scope => :user_id}
validates :uid, :presence => true, :uniqueness => {:scope => :provider}
belongs_to :user
end
This is my controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.from_auth(request.env['omniauth.auth'])
session[:user_id] = user.id
flash[:notice] = "Welcome #{user.nickname}"
redirect_to root_path
end
end
Thanks for your thoughts and pointers.
The problem is this bit of code:
Authentication.new(:provider => auth[:provider],
:uid => auth[:uid]
).attributes
This will return the full set of attributes, including the created_at and updated_at dates, which you're then passing to create, so mass assigning.
You could create the user, then build the attributes like so:
authentication = Authentication.find_by_provider_and_uid(auth[:provider],
auth[:uid]).try(:user)
unless authentication
user = create!(
:nickname => auth[:info][:nickname],
:email => auth[:info][:email])
user.authentications.build(:provider => auth[:provider])
end
I'm a newbie watching a Lynda.com video about rails 3. The teacher creates a method like this to find a user
def name
"#{first_name} #{last_name}"
end
He says this will return first name and last name for this user, but I don't understand how this function accesses first_name last_name, since there is no call to a database or no form parameters.
I know that without looking at the whole application it will be impossible for you to explain this, but you may be able to guess what this function might be dependent on.
this is the whole AdminUser model
require 'digest/sha1'
class AdminUser < ActiveRecord::Base
# To configure a different table name
# set_table_name("admin_users")
has_and_belongs_to_many :pages
has_many :section_edits
has_many :sections, :through => :section_edits
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
# standard validation methods
# validates_presence_of :first_name
# validates_length_of :first_name, :maximum => 25
# validates_presence_of :last_name
# validates_length_of :last_name, :maximum => 50
# validates_presence_of :username
# validates_length_of :username, :within => 8..25
# validates_uniqueness_of :username
# validates_presence_of :email
# validates_length_of :email, :maximum => 100
# validates_format_of :email, :with => EMAIL_REGEX
# validates_confirmation_of :email
# new "sexy" validations
validates :first_name, :presence => true, :length => { :maximum => 25 }
validates :last_name, :presence => true, :length => { :maximum => 50 }
validates :username, :length => { :within => 8..25 }, :uniqueness => true
validates :email, :presence => true, :length => { :maximum => 100 },
:format => EMAIL_REGEX, :confirmation => true
# only on create, so other attributes of this user can be changed
validates_length_of :password, :within => 8..25, :on => :create
before_save :create_hashed_password
after_save :clear_password
scope :named, lambda {|first,last| where(:first_name => first, :last_name => last)}
scope :sorted, order("admin_users.last_name ASC, admin_users.first_name ASC")
attr_protected :hashed_password, :salt
def name
"#{first_name} #{last_name}"
end
def self.authenticate(username="", password="")
user = AdminUser.find_by_username(username)
if user && user.password_match?(password)
return user
else
return false
end
end
# The same password string with the same hash method and salt
# should always generate the same hashed_password.
def password_match?(password="")
hashed_password == AdminUser.hash_with_salt(password, salt)
end
def self.make_salt(username="")
Digest::SHA1.hexdigest("Use #{username} with #{Time.now} to make salt")
end
def self.hash_with_salt(password="", salt="")
Digest::SHA1.hexdigest("Put #{salt} on the #{password}")
end
private
def create_hashed_password
# Whenever :password has a value hashing is needed
unless password.blank?
# always use "self" when assigning values
self.salt = AdminUser.make_salt(username) if salt.blank?
self.hashed_password = AdminUser.hash_with_salt(password, salt)
end
end
def clear_password
# for security and b/c hashing is not needed
self.password = nil
end
end
The method "name" is not finding a user from the database, however the variables inside it (first_name and last_name) are read from the corresponding database table fields. In this case assuming the usual rails conventions are followed you will find a database table called "AdminUsers" and inside it some fields of which one is first_name and another is second_name.
How this all works and why it is so can be found in the Ruby on Rails documentation for ActiveRecord
I am trying to set up the User model to successfully save user in the db but I'm hindered by, NameError: undefined local variable or method `hashed_password' for #<User:0x000001029fef18>
User model:
require 'digest'
class User < ActiveRecord::Base
attr_accessor :password
validates :email, :uniqueness => true,
:length => { :within => 5..50 },
:format => { :with => /^[^#][\w.-]+#[\w.-]+[.][a-z]{2,4}$/i }
validates :password, :confirmation => true,
:length => { :within => 4..20 },
:presence => true,
:if => :password_required?
has_one :profile
has_many :articles, :order => 'published_at DESC, title ASC',
:dependent => :nullify
has_many :replies, :through => :articles, :source => :comments
before_save :encrypt_new_password
def self.authenticate(email, password)
user = find_by_email(email)
return user if user && user.authenticated?(password)
end
def authenticated?(password)
self.hashed_password == encrypt(password)
end
protected
def encrypt_new_password
return if password.blank?
self.hashed_password = encrypt(password)
end
def password_required?
hashed_password.blank? || password.present?
end
def encrypt(string)
Digest::SHA1.hexdigest(string)
end
end
Add the hashed_password field to your users table by using a migration. It's currently missing.
My first bet is that hashed_password is not defined as a column in your model. Might want to check your migration file for this specific model
Add
attr_accessor :password, :password_confirmation
to Users.rb
I have the following models (with corresponding database tables) in my Rails 3 application:
class User < ActiveRecord::Base
has_many :service_users
has_many :services, :through => :service_users
attr_accessor :password
attr_accessible :password, :password_confirmation, :service_ids
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
...
end
class Service < ActiveRecord::Base
has_many :service_users
has_many :users, :through => :service_users
...
end
class ServiceUser < ActiveRecord::Base
belongs_to :service
belongs_to :user
end
#User Controller:
class UsersController < ApplicationController
...
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated."
redirect_to #user
else
#title = "Edit user"
render 'edit'
end
end
...
end
I want to be able to update a User model's associated services without having to specify the password and password confirmation attributes. How can I do this?
Two options...
If you have simple logic, like only validating the password when a user is created, this will work:
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 },
:if => :new_record?
More likely, you'll want a combination so that users can update their password:
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 },
:if => :is_password_validation_needed?
# Protect the password attribute from writing an
# empty or nil value
def password=(pass)
return if !pass.present?
#password = pass
end
private
def is_password_validation_needed?
# Return true if the record is unsaved or there
# is a non-nil value in self.password
new_record? || password
end
This could help:
http://railscasts.com/episodes/41-conditional-validations
you will want to look into conditional validation to specify whether or not the password attribute in your model should be validated when you are updating/saving the model. here is a Railscast episode that, while a little dated, is still fairly straightforward and should get you off on the right path