Rails | Validate email address wth specific extension - ruby-on-rails

Is there a way to validate email addresses such as 'myemail#mydomain.com' ?
So I should check if user has #mydomain.com extension on signup? How would regex code would look like?
This is what I am using currently, would like to add user.type = special if validation passes #mydomain.com if else user.type = normal
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }

You can add model level validation on email attribute
validates :email, format: { with: /#mydomain\.com\z/i }
However the above regex doesn't put any restrictions on part of email before #
Edit:
You will have to add a before_create action which does check for #mydomain.com
before_create :set_user_type
def set_user_type
if /#mydomain\.com\z/i.match(email)
self.type = :special
else
self.type = :normal
end
end

Related

ruby on rails - test for specific phone number of digits

This is my code
test 'phonenumber should be 11 digits' do
#user.phonenumber = 11
assert_not #user.valid?
end
this is my model validations, i am using the gem phonelibs
class User < ApplicationRecord
before_save { email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
validates :phonenumber, phone: { possible: true, allow_blank: true }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 256 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end
this already added the validations because it uses the Google libphonenumber and for Nigeria, it is 11
Phonelib.default_country = 'NG'
but it isnt testing for the exact digits of phone number
You've used a couple of length validations elsewhere - I'd suggest you need the same for your phonenumber field before it will fail validations for being too short.
I.E.
validates_length_of :phonenumber, is: 11
or
validates :phonenumber, length: { is: 11 }
or using a regex:
validates_format_of :phonenumber, with: /[0-9]{11}/
Docs can be found here - hope that helps!
PhoneLib has a lot of extra functionality based on countries and their phone number formats - the best approach here would be to dig properly into that and use their validations based on either a fixed or user-based location.
However, the above should work for ensuring the length of the phonenumber is 11.
Update:
The gem has a number of methods for checking validity of phone numbers, such as the following:
Phonelib.valid? '123456789'
Phonelib.valid_for_country? '123456789', 'XX'
You also need to configure the gem in config/initializers/phonelib.rb - if you could add that code to your question that would be useful.
However, to make use of this, your test could look something like:
test 'phonenumber should be 11 digits' do
#user.phonenumber = 11
assert_not Phonelib.valid?(#user.phonenumber)
end

How to set a virtual attribute in model with Rails?

I have a model User with usual attributes email, email_confirmation, password, password_confirmation. I use "has_secure_password" so the real attributes in the database are email and password_digest. However I would like to limit password length without spaces to 6 characters.
Here is my model :
class User < ActiveRecord::Base
before_validation :auto_strip_confirmation
validates :email, presence: true,
length: { maximum: MAX_SIZE_DEFAULT_INPUT_TEXT },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false },
confirmation: true
validates :email_confirmation, presence: true
has_secure_password
validates :password, length: { minimum: MIN_SIZE_USER_PASSWORD,
maximum: MAX_SIZE_USER_PASSWORD }
private
def auto_strip_confirmation
self.password.strip!
self.password_confirmation.strip!
end
end
But I get this in console :
> user.password = user.password_confirmation = "a "
=> "a "
> user.valid?
User Exists (0.8ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user#example.com') LIMIT 1
=> true
Thanks for your help.
After reload, my code actually works in console : user.valid? => false (thanks surendran). But my initial problem was in my tests : I thought I could not set virtual attributes because of the error message "undefined method `strip!' for nil:NilClass". But I forgot I test if my user is valid when password is nil, nearly like this :
before { user.password = nil) }
it { should_not be_valid }
before_validation comes before this test so he tries to strip a nil object.

Assigning to a class attribute from a method rails

Following the Michael Hartl rails tutorial. Struggling to get the remember token tests to pass, specifically, the test for non-blankness of the remember token.
The code for the User class is below
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save { :create_remember_token }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
and the test I can't get to pass:
subject { #user }
...
describe "remember token" do
before { #user.save }
its (:remember_token) { should_not be_blank }
end
and the error message I get is:
.....................F
Failures:
1) User remember token remember_token
Failure/Error: its (:remember_token) { should_not be_blank }
expected blank? to return false, got true
# ./spec/models/user_spec.rb:120:in `block (3 levels) in <top (required)>'
Finished in 0.68878 seconds
22 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:120 # User remember token remember_token
I don't know if this is relevant but sublime_text isn't doing anything with the self keyword (ie its not highlighting it in a different colour).
I'm using Ruby 1.9.3
The issue is that you're writing before_save { :create_remember_token } when you should have before_save :create_remember_token. The { } is a block. Same as when you do
do
#This is some code
end
That is also a block of code.
That's why your first before_save works, because you're giving the block a piece of code to execute. In the second before_save you're just giving it the name of the method to execute which has the block of code.
Tl:dr:
Change
before_save { :create_remember_token }
to
before_save :create_remember_token
and you should be good to go.

How do I remove validation duplication from a model?

Short of extracting shipping and billing addresses into an Address model, how can I remove this validation duplication?
I only want to validate the billing address if it's not the same as the shipping address. How would I go about extracting it into a module? An example would be really helpful as I never know what to include in modules, or self refers to.
validates :shipping_name, :shipping_address1, :shipping_street_number, :shipping_city, presence: true
validates :shipping_state, inclusion: { in: Address.states.values }
validates :shipping_post_code, length: { is: 5 }, numericality: { only_integer: true }
validates :billing_name, :billing_address1, :billing_street_number, :billing_city, presence: true, unless: -> { self.bill_to_shipping_address? }
validates :billing_state, inclusion: { in: Address.states.values }, unless: -> { self.bill_to_shipping_address? }
validates :billing_post_code, length: { is: 5 }, numericality: { only_integer: true }, unless: -> { self.bill_to_shipping_address? }
You can make a method and then pass in the bits that are different between the two types of addresses. In this case, the difference is the prefix word for the fields and the ability to pass in extra options.
module AddressValidator
def validates_address(type, options = {})
validates :"#{type}_name", :"#{type}_address1", :"#{type}_street_number", :"#{type}_city", {presence: true}.merge(options)
validates :"#{type}_state", {inclusion: { in: Address.states.values }}.merge(options)
validates :"#{type}_post_code", {length: { is: 5 }, numericality: { only_integer: true }}.merge(options)
end
end
class MyModel < ActiveRecord::Base
extend AddressValidator
validates_address(:shipping)
validates_address(:billing, unless: -> { self.bill_to_shipping_address? })
end

Hide password_digest error message in JSON output

I'm building a simple JSON API using the rails-api gem.
models/user.rb:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates :email, presence: true, uniqueness: { case_sensitive: false }, format: { with: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i }
validates :password, presence: { on: :create }, length: { minimum: 6 }
end
When I try to sign up without a password this is the JSON output I get:
{
"errors": {
"password_digest": [
"can't be blank"
],
"password": [
"can't be blank",
"is too short (minimum is 6 characters)"
]
}
}
Is it possible to hide the error message for password_digest? I'm returning the #user object with respond_with in the controller.
I've tried the following but no luck (it just duplicates the error "can't be blank"):
validates :password_digest, presence: false
#freemanoid: I tried your code, and it didn't work. But it gave me some hints. Thanks! This is what worked for me:
models/user.rb
after_validation { self.errors.messages.delete(:password_digest) }
You can manually delete this message in json handler in User model. Smth like:
class User < ActiveRecord::Base
def as_json(options = {})
self.errors.messages.delete('password_digest')
super(options)
end
end

Resources