Having trouble with users registering using our own company email address.
Example: I work at twitter. Users trying to use: user#twitter.com as their email address.
What would I add to the user model to block this from happening?
Try using a custom validation. Here is a super slimmed down example. You may want a bit more power, but this should get you started.
class User < ActiveRecord::Base
validates :email, blacklist: true
end
class BlacklistValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors.add attribute, (options[:message] || "is not a valid email") if
value =~ /twitter\.com/
end
end
Related
I need to validate email saving in email_list. For validation I have EmailValidator. But I cannot figure out how to use it in pair of validates_each. Are there any other ways to make validations?
class A < ActiveRecord::Base
serialize :email_list
validates_each :email_list do |r, a, v|
# what should it be here?
# EmailValidator.new(options).validate_each r, a, v
end
end
validates_each is for validating multiple attributes. In your case you have one attribute, and you need to validate it in a custom way.
Do it like this:
class A < ActiveRecord::Base
validate :all_emails_are_valid
...
private
def all_emails_are_valid
unless self.email_list.nil?
self.email_list.each do |email|
if # email is valid -- however you want to do that
errors.add(:email_list, "#{email} is not valid")
end
end
end
end
end
Note that you could also make a custom validator for this or put the validation in a proc on the validate call. See here.
Here's an example with a custom validator.
class A < ActiveRecord::Base
class ArrayOfEmailsValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.nil?
value.each do |email|
if # email is valid -- however you want to do that
record.errors.add(attribute, "#{email} is not valid")
end
end
end
end
validates :email_list, :array_of_emails => true
...
end
Of course you can put the ArrayOfEmailsValidator class in, i.e., lib/array_of_emails_validator.rb and load it where you need it. This way you can share the validator across models or even projects.
I ended up with this:
https://gist.github.com/amenzhinsky/c961f889a78f4557ae0b
You can write your own EmailValidator according to rails guide and use the ArrayValidator like:
validates :emails, array: { email: true }
Example:
Accepted extensions: "#blogsllc.org"
A user signs up with the email "joe#blogsllc.org" would be able to create an account.
Wondering what would be the best way to do this in Rails and how others would approach this? I imagined trying to check the format of the email address against a bunch of regular expressions but this could be tedious as the list of supported extensions grow.
The other way to do this would be to have a database of the supported extensions and check the created email address against the database to see if the extension is accepted but I'm not sure what would be the best way to implement this in Rails.
I'm looking to implement something similar to what Facebook did in it's early days.
Any help appreciated.
EDIT for misunderstanding:
If you don't need anything more fancy than a straight-up match of the domain (files have extensions, emails have domains), just splitting on # and matching the second part with a database column is the easiest way.
You can add the following code
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
class Person < ActiveRecord::Base
validates :email, :presence => true, :email => true
end
This Link will be useful
Trying to validate the email field in a rails devise app with a word exclusion.
validates :email, :exclusion => {:in => ["admin", "root",,
:message => "is reserved"}
Wich works great on the :username field but not on the email.
I suspect that Devise is "taken over" the validation of the email field and I need to super/ overrule the registrations controller of Devise.
How could I:
Prevent emails with words based on an :exclusion
Prevent emails with #myapp.com so users don't use the domain the app runs on.
You can always write custom validations to achieve what you want. Example from the guide:
The easiest way to add custom validators for validating individual
attributes is with the convenient ActiveModel::EachValidator. In this
case, the custom validator class must implement a validate_each method
which takes three arguments: record, attribute and value which
correspond to the instance, the attribute to be validated and the
value of the attribute in the passed instance.
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
class Person < ActiveRecord::Base
validates :email, :presence => true, :email => true
end
After checking if it is an e-mail, I would split the two validations. One for exclusion, and other for domain. You can retrieve the current domain when using passenger.
validate :email_username_is_not_on_blacklist, :email_domain_is_allowed
EXCLUDED_USERNAMES = "admin", "root"
EXCLUDED_DOMAINS = "myapp.com"
def email_username_is_not_on_blacklist
user, domain = email.split("#")
errors.add(:email, "E-mail user is not allowed") if self.class.EXCLUDED_USERNAMES.include?(user)
end
def email_domain_is_allowed
user, domain = email.split("#")
errors.add(:email, "E-mail domain is not allowed") if self.class.EXCLUDED_DOMAINS.include?(domain)
end
I have an object with multiple validations.
gist of the Approval model: https://gist.github.com/1579150 (side note, I know the Email Domain Validor doesn't work...)
The point is, if these validations fail, I want the object to save, but then set a value on approval.issue = true. Approval.issue is a boolean field that defaults to false, but then if the object fails validations I want the system admin to be able to see it and then handle it appropriately.
To make it more idiot proof, it would be nice to have some validations that can force the user to make changes, but then some would be exempt and would simply trigger the .issue field to true.
For instance, if the email is of the right domain but the email doesn't exist in the system, it would save it but then set issue => true. I could then set up a simple view for Approvals where :issue => :true. then the admin could modify or delete bad Approvals.
Ideas?
Code from gist:
class Approval < ActiveRecord::Base
class ApproverEmailValidator < ActiveModel::EachValidator
def validate_each(approval, attribute, value)
approval.errors[attribute] << "must be a valid e-mail address in our system" unless is_valid_email?(value)
end
protected
def is_valid_email?(address)
User.find_by_email(address)
end
end # End Approver Validator
class EmailDomainValidator < ActiveModel::EachValidator
def email_domain_is?(domain)
unless /ravennainteractive.com$/ =~ email(domain)
errors.add(:email, "You must Use an Eddie Bauer email address")
end
end
end #End Email Domain Validator
belongs_to :recommendation
attr_accessible :approval, :email, :user_id
validates :email, :email_domain
validates :next_approver_email, :approver_email => { :if => :recently_approved? }
before_save :create_next_approval
after_create :approval_notification
attr_accessor :next_approver_email
def recently_approved?
self.approved_changed? && self.approved?
end
def create_next_approval
next_approval = self.recommendation.approvals.build(:email => self.next_approver_email, :user_id => User.find_by_email(next_approver_email))
next_approval.save if next_approver_email.present? && recently_approved?
end
def email_domain_is?
unless /ravennainteractive.com$/ =~ email
errors.add(:email, "You must Use an Eddie Bauer email address")
end
end
private
def approval_notification
ApprovalMailer.needs_approval(self).deliver
end
end
You can implement observer for Approval that will analyze you objects before saving and set issue to "true", if there is some suspicious input.
UPDATE: Here is short guide how to implement observer:
rails generate observer - after this step you`ll see _observer.rb file.
Implement needed methods. Here is simple example extracted from one of my projects (It seems like you should use "before_save" method):
class HomeworkObserver < ActiveRecord::Observer
def after_create(homework)
TeacherMailer.send_later(:student_submitted_homework, homework)
end
def after_save(homework)
if (homework.checked)
StudentMailer.send_later(:teacher_checked_homework, homework)
end
end
end
Also you need to enable observer by adding it to your config/application.rb, e.g:
config.active_record.observers = :homework_observer
Official docs: http://api.rubyonrails.org/classes/ActiveRecord/Observer.html
When a user registers on my app they have to confirm their email, powered by Devise + Rails 3.
The email address defines the user's permissions so I don't want the user to be able to change it once registered. so removed :email from the users.rb attr_accessible which worked for a logged in user, but now user's can't register.
What's the right way to handle this? So users can't update their email but can register with their email using devise.
Thanks
This is the perfect case for a custom validator. Since Rails3, they are much easier to do than before.
class ImmutableValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << "cannot be changed after creation" if record.send("#{attribute}_changed?") && !record.new_record?
end
end
class User < ActiveRecord::Base
validates :email, :immutable => true
end
attr_readonly :email
That solved the problem easily.
https://groups.google.com/forum/#!topic/plataformatec-devise/skCarCHr0p8
I would personally leave the attr_accessible for :email and just remove the email field from the edit view. Also, you will want to strip out any email param from the params hash in the update action.