Rails update_attribute - ruby-on-rails

Ive got the following problem. I have a model called user which has a column named activated. Im trying to update that value whith the method activated?, but it gives me the error: Validation failed: Password can't be blank, Password is too short (minimum is 6 characters) Which doesnt make sense to me, because im not touching the password field! I just want to update the activated column. Im putting here the code I think its relevant, but if you think you need more just ask :)
Thank you very much in advance!
Model:
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation, :activated
has_many :sucu_votes
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => {:with => email_regex},
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:length => { :within => 6..15 },
:confirmation => true
before_save :encrypt_password
def activated?
self.update_attributes!(:activated => true)
return self.activated
end
Controller from which the method activated? is called
def activate
if request.get?
user=User.find_by_id(params[:id])
if user.activated?
flash[:notice]="Your account has been activated"
#redirect_to :controller => 'sessions', :action => 'new'
else
flash[:error]="We couldnt activate the account"
redirect_to :controller => 'sessions', :action => 'new'
end
end
end

Two things, first the ruby convention is to use predicate methods to return true or false only and not to do anything more like update a record. That is not causing your problem but is a deviation from what other programmers would expect. Secondly, instead of calling update_attributes try just calling:
update_attribute(:activated, true)
This should skip the rest of the callbacks for the record

Related

Rails 3 - how to skip validation rule?

I have for the registration form this validation rule:
validates :email,
:presence => {:message => 'cannot be blank.'},
:allow_blank => true,
:format => {
:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/,
:message => 'address is not valid. Please, fix it.'
},
:uniqueness => true
This rule check, if a user fill into the registration form email address (+ its correct format).
Now I am trying to add the opportunity to log in with using Twitter. Twitter doesn't provide user's email address.
How to skip in this case the validation rule above?
You can skip validation while saving the user in your code. Instead of using user.save!, use user.save(:validate => false). Learnt this trick from Railscasts episode on Omniauth
I'm not sure whether my answer is correct, just trying to help.
I think you can take help from this question. If i modify the accepted answer for your question, it will be like (DISCLAIMER: I could not test the following codes as env is not ready in the computer i'm working now)
validates :email,
:presence => {:message => 'cannot be blank.', :if => :email_required? },
:allow_blank => true,
:format => {
:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/,
:message => 'address is not valid. Please, fix it.'
},
:uniqueness => true
def email_required?
#logic here
end
Now, you update the email_required? method to determine whether it is from twitter or not! If from twitter, return false otherwise true.
I believe, you need use same :if for the :uniqueness validator too. otherwise it will. Though, i'm not sure too :(. Sorry
Skipping Individual Validations
Skipping individual validations requires a bit more work. We need to create a property on our model called something like skip_activation_price_validation:
class Product < ActiveRecord::Base
attr_accessor :skip_activation_price_validation
validates_numericality_of :activation_price, :greater_than => 0.0, unless: :skip_activation_price_validation
end
Next we will set the property to true any time we want to skip validations. For example:
def create
#product = Product.new(product_params)
#product.skip_name_validation = true
if #product.save
redirect_to products_path, notice: "#{#product.name} has been created."
else
render 'new'
end
end
def update
#product = Product.find(params[:id])
#product.attributes = product_params
#product.skip_price_validation = true
if #product.save
redirect_to products_path, notice: "The product \"#{#product.name}\" has been updated. "
else
render 'edit'
end
end
You seem to be doing two separate validations here:
If a user provides an email address, validate it's format and uniqueness
Validate the presence of an email address, unless it's a twitter signup
I would do this as two separate validations:
validates :email,
:presence => {:message => "..."},
:if => Proc.new {|user| user.email.blank? && !user.is_twitter_signup?}
validates :email,
:email => true, # You could use your :format argument here
:uniqueness => { :case_sensitive => false }
:unless => Proc.new {|user| user.email.blank?}
Additional info: validate email format only if not blank Rails 3
The best way would be:
It would validate the email when the user is not signed in from twitter as well as skip email validation when signed from twitter.
validates :email,
:presence => {:message => 'cannot be blank.'},
:allow_blank => true,
:format => {
:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/,
:message => 'address is not valid. Please, fix it.'
},
:uniqueness => true
unless: Proc.new {|user| user.is_twitter_signup?}

rails password update validation issue

I have the following validation:
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..40 }, :format => { :with => pass_regex }, :unless => :nopass?
Then, when I try to update without password (nopass? is true) the following errors appear:
There were problems with the following fields:
Password is too short (minimum is 6 characters)
Password is invalid
Notice that the :unless works on :presence and :confirmation but not in :lenght or :format.
How could I fix this?
I've had some strange issues with the :confirmation flag as well, which I never figured out, but that's how I solved the problem in my Rails 3.0.x app:
attr_accessor :password_confirmation
validates :password, :presence => true, :length => {:within => PASSWORD_MIN_LENGTH..PASSWORD_MAX_LENGTH}
validate :password_is_confirmed
def password_is_confirmed
if password_changed? # don't trigger that validation every time we save/update attributes
errors.add(:password_confirmation, "can't be blank") if password_confirmation.blank?
errors.add(:password_confirmation, "doesn't match first password") if password != password_confirmation
end
end
I realise this is not an explanation why your code isn't working, but if you're looking for a quick temporary fix - I hope this will help.
You might use conditional validations
class Person < ActiveRecord::Base
validates :surname, :presence => true, :if => "name.nil?"
end

Undefined method password_changed? Error

I'm trying to set my program so that the password only is validated if it is changed (so a user can edit other information without having to put in their password).
I am currently getting an error that says
NoMethodError in UsersController#create, undefined method `password_changed?' for #<User:0x00000100d1d7a0>
when I try to log in.
Here is my validation code in user.rb:
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :if=>:password_changed?
Here is my create method in users_controller.rb:
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome to the Sample App!"
redirect_to #user
else
#title = "Sign up"
render 'new'
end
end
Thank you!
Replace with:
:if => lambda {|user| user.password_changed? }
I'd do two different validations:
validates :password, :presence =>true, :confirmation => true, :length => { :within => 6..40 }, :on => :create
validates :password, :confirmation => true, :length => { :within => 6..40 }, :on => :update, :unless => lambda{ |user| user.password.blank? }
I encountered this same problem and after reading this post I implemented the code suggested by apneadiving in his answer but with a slight modification:
I used two different validations, one for create:
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..128 }, :on => :create
and then I used this one for update:
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..128 }, :on => :update, :unless => lambda{ |user| user.password.to_s.empty? }
Originally, I Implemented exactly what apneadiving suggested, but I realized that on updates to the user it wasn't actually validating the presence of a string. As in, it was allowing a user to set their password to " " (A string of whitespace). This is due to the fact that " ".blank? == true, and so if you have it set to validate like this:
:unless => lambda { |user| user.password.blank? }
Then it won't run the validation if a string full of whitespace is submitted by the user is submitted because it reads the string as being blank. This essentially invalidates the effect of validating for presence on the update. The reason I did password.to_s.empty? instead of simply password.empty? is to prevent errors if someone calls update_attributes on the user model and doesn't pass in anything into the password, field, then the password will be nil, and since the ruby nil class doesn't have an empty? method, it will throw an error. Calling .to_s on nil, however will convert it to an empty string, which will return true on a successive .empty? call (thus the validation won't run). So after some trials and tribulation I found that this was the best way to do it.
Ended up here googling this error message, and using
#account.encrypted_password_changed?
in my case yielded what I wanted.
The change to look for, in Rails 4 at least, is password_digest.
#account.password = "my new password"
#account.changes # => {"password_digest"=>["$2a$10$nR./uTAmcO0CmUSd5xOP2OMf8n7/vXuMD6EAgvCIsnoJDMpOzYzsa", "$2a$10$pVM18wPMzkyH5zQBvcf6ruJry22Yn8w7BrJ4U78o08eU/GMIqQUBW"]}
#account.password_digest_changed? # => true

Rails Validates Prevents Save

I have a user model like this:
class User < ActiveRecord::Base
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
.
.
.
end
In the User model, I have a billing_id column I want to save into from a OrdersController which looks like this:
class OrdersController < ApplicationController
.
.
.
def create
#order = Order.new(params[:order])
if #order.save
if #order.purchase
response = GATEWAY.store(credit_card, options)
result = response.params['billingid']
#thisuser = User.find(current_user)
#thisuser.billing_id = result
if #thisuser.save
redirect_to(root_url), :notice => 'billing id saved')
else
redirect_to(root_url), :notice => #thisuser.errors)
end
end
end
end
Because of validates :password in the User model, #thisuser.save doesn't save. However, once I comment out the validation, #thisuser.save returns true. This is an unfamiliar territory for me because I thought this validation only worked when creating a new User. Can someone tell me if validates :password is supposed to kick in each time I try to save in User model? Thanks
You need to specify when you want to run your validations otherwise they will be run on every save call. This is easy to limit, though:
validates :password,
:presence => true,
:confirmation => true,
:length => { :within => 6..40 },
:on => :create
An alternative is to have this validation trigger conditionally:
validates :password,
:presence => true,
:confirmation => true,
:length => { :within => 6..40 },
:if => :password_required?
You define a method that indicates if a password is required before this model can be considered valid:
class User < ActiveRecord::Base
def password_required?
# Validation required if this is a new record or the password is being
# updated.
self.new_record? or self.password?
end
end
It's likely because you are validating that the password has been confirmed (:confirmation => true), but the password_confirmation does not exist.
You can break this out to something like:
validates_presence_of :password, :length => { :within => 6..40 }
validates_presence_of :password_confirmation, :if => :password_changed?
I like this approach because if the user ever changes their password, it will require the user entered the same password_confirmation.

Why aren't my before_validation methods firing if some validation is scoped?

In my model I've got a couple of methods to populate attributes of an Invoice before it is validated:
validates :account_id, :presence => true
validates :account_address, :presence => true
validates :number, :presence => true
validates :number, :uniqueness => true, :scope => :client_id
before_validation :generate_number, :associate_addresses, :on => :create
def generate_number
self.number = self.client.invoices.count + 1
end
def associate_addresses
self.account_address = self.account.addresses.first
end
And in the controller:
#invoice = #account.invoices.build(:client_id => #client.id)
if #invoice.save
#it saved
end
My problem is that the associate_addresses and generate_number methods only fire if I remove the :scope => :client_id argument on the :number validation.
Why would it skip the before_validation callbacks due to this?
Working in Rails 3.0.3
Thanks!
Thanks.
Don't know why it's skipping the before_validation methods, but to scope a uniqueness validation in Rails 3 you should use the following syntax:
validates :number, :presence => true, :uniqueness => { :scope => :client_id }
I guess that your syntax is making it try to add a scope validation, which doesn't exist. Probably there's a Rails bug that makes that skip the before_validation methods.

Resources