Validation on missing attributes on update_attributes - ruby-on-rails-3

The question is very simple, does update_attributes validates every possible validation of the model, even if I don't want to update some of the attributes?
I have a edit view, where the user might change his password, but only if he passes it, i.e., if it's blank the password would not change.
So I do the following in the controller:
def update
params[resource_name].delete(:password) if params[resource_name][:password].blank?
params[resource_name].delete(:password_confirmation) if params[resource_name][:password_confirmation].blank?
params[resource_name].delete(:current_password) if params[resource_name][:current_password].blank?
if resource.update_attributes(params[resource_name])
...
end
end
I defined the following validation on the model:
validates :password,
:length => { :within => 6..40 }
So whenever i use call the update I get an error saying that the password is too short
Ps.: I'm using Devise to deal it this.
EDIT: Do any of you know if Devise already have any validation on the password? Cause, I removed the validation and it worked in the right way, but if I put a short password it still show a validation, saying it's too short.

Yes, Devise does provide validations on password if you've passed :validatable to the devise method in your model. The default configuration for password length is 6..128. You can override this in config/initializers/devise.rb (around line 101).
You can remove :validatable from your model and write your own validations if you prefer. If you do this and don't want the validation to run if the password isn't passed to update_attributes, then do something like this:
validates :password, :presence => true, :if => lambda { new_record? || !password.nil? }

Related

Delayed job and Mandrill: uninitialized constant Mandrill::API

I have mailer service where users can upload an .xls file with emails and some other user related data to send an email campaign.
I was having some timeout issues since it takes some seconds to process (as I do some validation and configuration for each email to be sent, eg: save records to database, check if an email was sent in the last 30 days, create personalised html code for each email (to create links that contain the email address as a parameter, etc).
After some research, moving this to a delayed job seemed reasonable, as suggested in this rails cast. The only problem is that I am having an error that says uninitialized constant Mandrill::API, it seems that when I run the job, the call require 'mandrill' doesn't work.
I created the task in my model file. Something like this
class Mailer < ActiveRecord::Base
attr_accessible :email, :lastname, :name
def self.send_mail(emails)
[...a lot of code here...]
require 'mandrill'
m = Mandrill::API.new ENV['MANDRILL_APIKEY']
message = {
:subject=> template.subject,
:from_name=> template.from_name,
:from_email=> from + "#" + email_domain,
:to=>mails,
:global_merge_vars=> [
{ :name => 'GREETING', :content => template.greeting},
{ :name => 'CONT1', :content => template.message},
{ :name => 'IMAGE', :content => image_url},
],
:html=>email_template,
:preserve_recipients => false,
:merge_vars => email_contents,
}
sending = m.messages.send message
end
end
from my controller I call Mailer.send_mails(emails) and it works just fine, but if I call Mailer.delay.send_mails(emails) I get the error. How can I fix this?
I have tried adding require 'mandrill' at the beginning of the class, before and after class Mailer < ActiveRecord::Base but nothing seems to work
Make sure to restart the delayed_job daemon to pick up any code changes. It does not auto-reload like the Rails development environment does.

Update user attributes without changing password in rails_admin

In my app, I use devise to generate User model, add some attributes like job, role,... to this.
In rails_admin page, when edit an user, I only show fields: email, job, role, idcard (no include password and password_confirmation fields)
When I click Save, it show error because the password is shorter than 6 characters.
In the console, if I try
User.last.update_attributes(:role => "admin", "idcard" => "1233131")
It'll get the same error!
How can I fix this? Because the rails_admin (I think and be sure) didn't use update in registrations_controller to update user!
oh, yeah! I just fix my own problem by delete two validate of user model
validates :password, :length => { :minimum => 6 }
validates :password, :confirmation => true
and when I type
User.first.update_attributes(:email => "abc#yahoo.com")
It worked!!!

Active record callbacks. How are they able to access variables/scope?

I'm new to Ruby on Rails and I'm hung up on using Active Record callbacks. I know how to use them, but I'm trying to truly understand what is happening, and I'm not getting it. My confusion has to do with variable scopes in Ruby.
Here is a simple Active Record class for a user with fields: email, password_hash, password_salt
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
#validation
validates :password, :confirmation => true
validates :email, :password, :presence => true
validates :email, :uniqueness => true
#When saving the user, encrypt the password
def encrypt_password
#First check if the password is present
if (password.present?)
#encrypt the password
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
In the method "encrypt_password", how is the variable "password" accessible? Is it the same as self.password (object var?), and is this not the same as #password? (why?)
In the actual encryption routine, I invoke self.password_salt. I noticed that I can simply type in "password_salt" (without reference to self) and it doesn't work. Why not? Why is this different from #password_salt?
Sorry if this comes across as noobish, I've spent a good couple of hours bashing away at this, and I'm struggling to understand this.
1) It is the same as self.password. ActiveRecord defines methods, not instance variables to access stuff related to the database. That's why you cannot access it with #password.
2) You need to use self.password_salt= because otherwise you'd be assigning a local variable, not doing a method call.
PS: Callbacks are only method calls on your object. The only difference is that Rails calls them for you, not yourself.

Two forms conflict

In update user form, I want to split password from rest of the form.
In user model I validate it.
I want to have
form 1
User infos fields
form 2
password and confirm fields.
in php I would do something like if post password is empty, ignore it.
is there something like
if :password
do validation
end
I need the model part, I have the rest.
just need an idea how to split validation in model or how to achieve this.
I hope i did understand you
class User << AR
validates :password,
:lenght => {:between => 3..20},
:confirmation => true,
:if => Proc.new { self.password }
end

"Email is already taken" error when user logs in with client_side_validations and devise

I am trying to use both client_side_validations and devise in my Rails app, and get a weird bug in the log in form.
It's says that the email has already been taken and doesn't let the user to log in :)
Email is used as the login.
This is only when I set the :validate => true.
When I turn off the setting :validate => true, the log in is performed successfully.
What might cause this problem?
I got the answer from the author of the client_side_validations:
For login form you don't want to have the uniqueness validator. So you'll need to do something like:
f.text_field :email, :validate => { :uniqueness => false }
From what I've understood this is the workaround because of the conditional validations in devise.