How to do conditional statement of validation from controller name in model - ruby-on-rails-3

Example:
account_controller: do not validate a password
password_controller: validate a password
my idea is...
class User
include Mongoid::Document
...
validates :username,
:presence => true
validates :password,
:presence => { :if => :passord? }
...
def password?
# self.controller.to_s == 'password'
end
end
First of all, my idea is wrong?
Anyone have another good idea?

You can add virtual attribute to your model and conditional validation:
class User
attr_accessor :skip_password_validation
validates :password, :unless => :skip_password_validation
end
And put something like this into controller:
user.skip_password_validation = true

Related

Activerecord adds additional conditions in query

For example I am doing something like this:
PlatformInformer.where(1)
and result query via
PlatformInformer.where(1).to_sql
is
SELECT `platform_informers`.* FROM `platform_informers` WHERE `platform_informers`.`platform` = 'android' AND `platform_informers`.`email` = 'voldemar#klops.ru' AND (1)
I didn't ask to add email and platform fields in where clause!
This problem causes when I am executing code inside PlatforInformer model methods. Default scope is doesn't set. What is the root of evil?
Rails 3.2.13
UPDATE:
class PlatformInformer < ActiveRecord::Base
include HasUniqueGenerator
attr_accessible :email, :platform,:secret_code,:activated,:invitation_sent
before_create :init_secret_code
PLATFORMS = %w(windows macos android ios)
def self.PLATFORMS
PLATFORMS
end
validates :platform, :presence => true,:inclusion => { :in =>PLATFORMS }
validates :email, :presence => true, :email => true
validates_uniqueness_of :email, scope: :platform
scope :confirmed, Proc.new { where(:activated => true) }
def several_platforms?
PlatformInformer.confirmed.find_all_by_email(self.email).count > 0
end
def send_confirmation
if already_subscribed?
activate!
else
PlatformInformerMailer.inform_me(self.id).deliver
end
end
def activate!
PlatformInformer.where(:email=>self.email).update_all(:activated=>true)
end
private
def init_secret_code
gen_unique_code :secret_code, 16
end
def already_subscribed?
PlatformInformer.confirmed.where(email: self.email).any?
end
end
Problem was in using first_or_create method, that created virtual scope with email and platform attributes.

Rails nil value when saving to database

I am trying to implement a user authentication system inside rails, this is my model:
class User < ActiveRecord::Base
attr_accessible :id, :email, :name, :password, :created_at, :updated_at
has_secure_password
before_save { email.downcase! }
validates :email, presence: true, :uniqueness => { :case_senstive => false }
validates :name, presence: true
validates :password, presence: true, length: { minimum: 6 }
end
Running in the console i can read the User table successfully, then when i try to create a record:
User.new(:name => "A", :email => "a#a.a", :password => "password")
running valid on it retrurns true, but when saving the record, i get error:
users.password may not be NULL
Extracting the password out of the hash works fine.
What is the problem?
Thanks
Where are you setting :password_confirmation? The example in the docs suggests you need it.
http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html
Main problem is in has_secure_password. If you are using that you should have string field :password_digest (it's where your encrypted password will be saved). And you need delete field :password and your validator of presence for that too. After add gem 'bcrypt-ruby', '~> 3.0.0' .
And now that should work
user = User.new(:name => "A", :email => "a#a.a",
:password => "password", :password_confirmation => "password")
But better use great gem https://github.com/plataformatec/devise . It has everything you need.
NEW ADDED
you should have attr_accessible for :password_confirmation too and that field should be used in your form.
more info about has_secure_password

Options for validates_with

I'm not able to access the values, passed as option in 'validates_with'
My model:
class Person < ActiveRecord::Base
include ActiveModel::Validations
attr_accessible :name, :uid
validates :name, :presence => "true"
validates :uid, :presence => "true"
validates_with IdValidator, :attr => :uid
My Custom Validator:
Class IdValidator < ActiveModel::Validator
def validate(record)
puts options[:attr]
...
...
end
end
For testing purpose, I'm printing "options[:attr]" and all I see is ":uid" in the terminal and not the value in it. Please help!
When you pass in :attr => :uid, you're just passing in a symbol. There's no magic happening hereā€”it just takes the hash of options you've attached and delivers it as the options hash. So when you write it, you see the symbol you've passed.
What you probably want is
Class IdValidator < ActiveModel::Validator
def validate(record)
puts record.uid
...
...
end
end
Because validates_with is a class method, you can't get the values of an individual record in the options hash. If you are interested in a more DRY version, you could try something like:
class IdValidator < ActiveModel::Validator
def validate(record)
puts record[options[:field]]
end
end
class Person < ActiveRecord::Base
include ActiveModel::Validations
attr_accessible :name, :uid
validates :name, :presence => "true"
validates :uid, :presence => "true"
validates_with IdValidator, :field => :uid
end
Where you pass in the name of the field you want evaluated.

Rails validation error email is too short, email is invalid

In attempting to seed my database I ran into a validation error on my User model's email attribute. The error:
Validation failed: Email is too short (minimum is 5 characters), Email is invalid
The thing is, my email is xxxxxxxx#gmail.com. I have five characters. Sorry for the beginner question but I don't know what is going on. I recently followed Railscasts to reset a User's password, and enable CanCan. I'm not sure if CanCan would affect anything, but prior to exploring that new functionality I've been able to fully seed my database without problems. I've pasted in some of my code below. I'm running Rails 3.0.5 and Ruby 1.9.2.
An example of how I create a User in my seed file:
me = User.create(:email => 'me#gmail.com', :password => 'test', :profile => my_profile)
User.rb model:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :password, :password_confirmation
before_save :encrypt_new_password
before_create { generate_token(:auth_token) }
before_validation :downcase_email
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
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?
Add :email to attr_accessible to allow mass assignment on it. Without that the email field will not even be set so validation will fail.

Why is user.save true but email shows as nil?

I'm using a nested model form for sign-up and am working through the kinks as a beginner. One issue that popped up in particular though that I don't really get is user.email is returning as nil.
Before I started playing around with the nested model form, I could create records in the console wihtout a problem. Now, however I can't create records and some of the latest records created have nil as their email. (I'm not sure if it has anything to do with the nested model at all, but that's my reference point for when it started going haywire.)
If I go into rails console to create a new User/Profile, I follow this process:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.first_name = ""
...
user.profile.save
user.save
Everything goes well until user.save, which gives me the NameError: undefined local variable or method 'params' for #<User:>. In rails console it pinpoints to user.rb:25 in create_profile
So here is my User model:
class User < ActiveRecord::Base
attr_accessor :password, :email
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
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?
before_save :encrypt_new_password
after_save :create_profile
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
Can anyone help me figure out what's going on?
UPDATE: I tried changing my regex but I'm still seeing nil for email. Though a prior SO post said not to blindly copy regex without testing, so maybe I just didn't test it correctly. Good news though: I no longer get the error.
attr_accessor simply defines a "property" on the object and has no relation to the attributes of a ActiveRecord model (attributes is a Hash of the fields and values obtained from a table).
ActiveRecord does not save such "properties" as defined by the attr_accessor. (Essentially, attr_accessor defines a attr_reader and attr_writer (i.e. "getter" and "setter") at the same time)