Using the Simple Form gem, how can I only allow a user to submit the form only if their email has not yet been used to submit a form.
In addition to Venom's answer, I recommend using unique index.
Because there may be a situation when there will be requests with the same email at the same time. And they will be validated. In this case, you will have duplicates.
For this purpose make constraints. It will be something like
$ rails g migration AddIndexToObjects
class AddIndexToObjects < ActiveRecord::Migration
def change
add_index :objects, :email, unique: true
end
end
Use it in your model which has an email field, and not in your controller, add the following code
validates :email, uniqueness: true
what does this code do?
This will prevent users to use email id which are already present in your database. don't forget to check right if I'm correct.
Thanks.
Related
I have a User model with an email attribute. Various parts of my app conceive of an "email" differently; sometimes as a string, sometimes as a hash ({ token: 'foo', host: 'bar.com' }), sometimes as an object. This is bad; I want the concept of an email to be consistent wherever I use it.
So, I use an Email object that does what I want. I don't see any good reason to create an Email table; instead, I just want to create a new Email object corresponding to an email string whenever I need one. Therefore User looks like this:
class User < ActiveRecord::Base
def email
Email.new(read_attribute :email)
end
def email= email
write_attribute :email, email.to_s
end
end
However, this causes at least two issues:
I can't search for a user by email without an explicit call to to_s.
I can't run a uniqueness validation on the email column anymore. I get a TypeError: can't cast Email to string. (I can fix this with a custom validator.)
Questions:
Is there something wrong with this approach? The fact that it breaks my validation is a code smell to me.
Is there some way to get the existing validates :email, uniqueness: { case_sensitive: false } validation to work with these new accessor definitions?
I have a Company model and an Employer model. Employer belongs_to :company and Company has_many :employers. Within my Employer model I have the following validation:
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
I'm running into a problem where the above validation fails. Here is an example setup in a controller action that will cause the validation to fail:
company = Company.new(company_params)
# company_params contains nested attributes for employers
company.employers.each do |employer|
employer.password = SecureRandom.hex
end
company.employers.first.role = 'Admin' if client.employers.count == 1
company.save!
admin = company.employers.where(role: 'Admin').order(created_at: :asc).last
admin.update(some_attr: 'some_val')
On the last line in the example code snippet, admin.update will fail because the validation is checking to see if company_id is included in the list, which it is not, since the list was generated before company was saved.
Obviously there are ways around this such as grabbing the value of company.id and then using it to define admin later, but that seems like a roundabout solution. What I'd like to know is if there is a better way to solve this problem.
Update
Apparently the possible workaround I suggested doesn't even work.
new_company = Company.find(company.id)
admin = new_company.employers.where(role: 'Admin').order(created_at: :asc).last
admin.update
# Fails validation as before
I'm not sure I understand your question completely, but there is an issue in this part of the code:
validates :company_id, inclusion: {in: Company.pluck(:id).prepend(nil)}
The validation is configured on the class-level, so it won't work well with updates on that model (won't be re-evaluated on subsequent validations).
The docs state that you can use a block for inclusion in, so you could try to do that as well:
validates :company_id, inclusion: {in: ->() { Company.pluck(:id).prepend(nil) }}
Some people would recommend that you not even do this validation, but instead, have a database constraint on that column.
I believe you are misusing the inclusion validator here. If you want to validate that an associated model exists, instead of its id column having a value, you can do this in two ways. In ActivRecord, you can use a presence validator.
validates :company, presence: true
You should also use a foreign key constraint on the database level. This prevents a model from being saved if there is no corresponding record in the associated table.
add_foreign_key :employers, :companies
If it gets past ActiveRecord, the database will throw an error if there is no company record with the given company_id.
I have a Rails 3.2.18 app where I'm trying to do some conditional validation on a model.
In the call model there are two fields :location_id (which is an association to a list of pre-defined locations) and :location_other (which is a text field where someone could type in a string or in this case an address).
What I want to be able to do is use validations when creating a call to where either the :location_id or :location_other is validated to be present.
I've read through the Rails validations guide and am a little confused. Was hoping someone could shed some light on how to do this easily with a conditional.
I believe this is what you're looking for:
class Call < ActiveRecord::Base
validate :location_id_or_other
def location_id_or_other
if location_id.blank? && location_other.blank?
errors.add(:location_other, 'needs to be present if location_id is not present')
end
end
end
location_id_or_other is a custom validation method that checks if location_id and location_other are blank. If they both are, then it adds a validation error. If the presence of location_id and location_other is an exclusive or, i.e. only one of the two can be present, not either, and not both, then you can make the following change to the if block in the method.
if location_id.blank? == location_other.blank?
errors.add(:location_other, "must be present if location_id isn't, but can't be present if location_id is")
end
Alternate Solution
class Call < ActiveRecord::Base
validates :location_id, presence: true, unless: :location_other
validates :location_other, presence: true, unless: :location_id
end
This solution (only) works if the presence of location_id and location_other is an exclusive or.
Check out the Rails Validation Guide for more information.
So I'm working on the registration aspect of the site currently. I have a main sign up which is just full name, email and password. (aka new.html.erb)
After you fill in that information I direct you to a new site (setup.html.erb) and ask for more info like city, country etc.
On that you also have the edit profile account.
I am trying to make my app more secure and adding restrictions and presence etc in the model. However how can I limit them.
Currently if I do
validates :email, presence: true,
and I go to a form that doesn't even contain the email for nor permits it I get an error up that I need to add an email.
Also how do I fix this: I make presence true, I input require in html5. But still if I go to my source code and just remove the form and push submit it saves and I can bypass adding info.
Currently if I do validates :email, presence: true,
and I go to a form that doesn't even contain the email for nor permits it I get an error up that I need to add an email.
Fix:
what you need is a conditional validation. If we look at rail guides it says
Sometimes it will make sense to validate an object only when a given predicate is satisfied. You can do that by using the :if and :unless options, which can take a symbol, a string, a Proc or an Array.
So in your model you could do something like:
class Order < ActiveRecord::Base
validates :email, presence: true, if: :need_to_validate?
def need_to_validate?
#your condition to check whether you want email validation or not
end
end
Update:
You can use params[:action] and params[:controller] smartly to check in which action and controller(hence which view) you currently are in so your method would be:
def need_to_validate?
params[:action] == your_view_action && params[:controller] == your_controller_name #your condition to check whether you want email validation or not
end
I'm developing an app that requires the user to enter info into a form. Its has basic validation on some of the fields to check that the're not blank.
The user model has many user_entries
has_many :user_entries, dependent: :destroy
and the user_entry model belongs to user
belongs_to :user
the problem arises with the validation in the user_entry model
validates :name, :address, :email, presence: true
before adding the foreign key user_id to the user_entries table this code worked fine, I could fill out the form with no problem and add the entries to the table. But I need to capture the current user id within the user_entries table so I can trace an entry to a user.
def create
#user_entry = UserEntry.new(params[:user_entry])
#user_entry.add_comp_connections_from_entered_competition(current_entered_competition)
#user = current_user
#user_entry = #user.user_entries.build
#--etc--#
removing the validation lets me do this, but I don't want to remove it. It seems that removing the foreign key lets me validate. But I want both to work, any help would be very much appreciated, thanks
As stated by SteveTurczyn changing
#user = current_user
#user_entry = #user.user_entries.build
to just
#user_entry.user = current_user
makes the code work, like solving so many problems its a case of not over complicating things.
thanks again Steve Turczyn