I have a problem with mongoid. I have validation on some field, called flickr_id. The problem is, that Mongo doesn't support transactions and sometimes, somehow, despite the fact that there is validates :flickr_id, :uniqueness => true, there are duplicates in a database. How can I remove them from Rails application? Because anytime I want to do something with these objects which aren't unique, I get an error that it's not valid. How can I ignore validation in such situation?
I'm using validates_uniqueness_of an works as expected. Assuming that what you want is to clean your DB, you can comment that line and remove duplicated documents through console.
If not the case, you can add on to your validation, so the validation is only run when creating/updating but not when destroying:
:on Only run when specified, supports :create and :update.
More info here.
Try object.delete instead of object.destroy.
Related
I would like to add a :presence and :uniqueness validation to a model in Rails. I'm using MongoDB and the Mongoid gem.
I have a model that is already in use and have existing records in the DB. I'd like to add a new :field and then add validations for :presence and :uniqueness for the field.
I know that by default, any existing records will simply add the :field and the result will be null unless I specify a :default.
My question is, since I want this new :field to be unique, will this cause an error for the existing records in the DB that will be null? Will I lose these records or does Rails just apply the validations to the new records?
Rails/AciveRecord will not ignore or delete your old records...
Validations work as follows: they are only used/checked when you try to write stuff to the database, e.g. when you create a new record or when you update a record. So in your case you will get validation errors when you try to update an old record without adding the new required fields.
I suggest that you try to clean up your database when adding the new fields (meaning adding sensible defaults to old records for the new required fields).
I'm using rails 2.3.5 and Authlogic in our website, and I have been getting errors on the database through hoptoad of users with duplicated emails trying to be saved. The problem is, obviously I have the validates_uniqueness_of :email on the model.
On my tests here in development I get the expected validation error and the user is not saved, but in production, I keep getting this errors on the DB layer.
I've tested with case sensitive emails and it also validated correctly.
I've checked and the class and there is no attr_accessor or any other attribute override, and I don't think Authlogic would do it in a wrong way...
What could be happening in production? Are there any cases where rails validates doesn't work?
Locate the SQL running validates_uniqueness_of in your development log, and if you see something like WHERE (email = BINARY 'foo#example.com'), try creating a user with FOO#EXAMPLE.COM and now you can reproduce the DB-level duplicate exception.
To fix this, put the following code in config/initializers/patches.rb:
class ActiveRecord::ConnectionAdapters::Mysql2Adapter
def case_sensitive_equality_operator
"="
end
end
Note that Mysql2Adapter should be MysqlAdapter if you're on Rails 2.
On a side note, it is a longstanding bug in Rails IMO - handling case-sensitivity in Ruby level doesn't make sense at all. If you need case-sensitive lookup, you should have the column collation of utf8_bin. If you need case-insensitive lookup, you should have the column collation of utf8_general_ci. Applying BINARY function in the where clause will disable the use of index, and validates_uniqueness_of causes full table scan every time you try to create/update a record. If you have millions of records, you're totally screwed. The patch above will fix that, too - in fact, it was my original motivation to create that patch.
If you agree, please +1 to https://github.com/rails/rails/issues/1399 :)
Have you tried recreating the scenario. Why should throw errors that warrant Hoptoad Notification. I mean, basically if you have a it should not save the user and not throw an error for hoptoad to notify you about.
Also with authlogic, i don't think you are required to specify the validate_uniqueness_of for email. Usually authlogic will take care of that for you.
So I guess, its time for you to deep dive.
Look at the logs, and try recreating this error locally. Its always best to retrace the steps leading to error.
More details, error stack , code would definitely be helpful.
Just a guess but could it be that your email column allows null, validates_uniqueness_of is ignoring nil (or blank) values and that your users are trying to register without specifying their email addresses?
I'm working on a project in Rails 3 where I need to create an empty record, save it to the database without validation (because it's empty), and then allow the users to edit this record in order to complete it, and validate from then on out.
Now I've run into a pretty basic problem: I can't seem to save a model without validating it under any circumstances.
I've tried the following in the console:
model = Model.new
model.save(false) # Returns RuntimeError: Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
model.save( :validate => false ) # Returns same error as above
model = Model.create
model.save(false) # Same runtime error
model.save( :validate => false ) # Same runtime error
I then tried changing all the validations in the model to :on => :update. Same error messages on any attempt to save.
So what am I missing here? How can I create an empty record and then let validation occur as the user edits it?
Thanks!
It is a bad practice to have invalid models saved by normal use cases. Use conditional validations instead:
validates_presence_of :title, :unless => :in_first_stage?
or if you have many:
with_options :unless => :in_first_stage? do
validates_presence_of :title
validates_presence_of :author
end
This way nothing stands in way to have nightly integrity tests, which checks all records for validity.
A valid use case for saving without validations would be for testing edge cases, e.g. to test that a database constraint is enforced.
*sigh...*
Found the problem... one of my after_validate method calls was adding information and resaving the model, hence the errors I was getting weren't from the console input, they were coming from the after_validate method which was saving again.
Thanks all.
For emergencies only
Assuming that you have considered this very carefully and are certain that this is a good idea, you can save without validation using:
my_model.save validate: false
There are almost no valid use cases for this, and it should be considered an emergency one off procedure. Your use case does not qualify.
Problems with invalid records
Having invalid records in the database leads to all manner of problems down the line. For example, you send an email to all users and update a 'last_contacted_at' field on your user model. Your invalid users will not be updated and will descend into an email spiral of death.
Conditional validation
As other posters have pointed out, conditional validation will solve most issues for which you might otherwise have used validate: false.
Instead of placing an invalid model in the database, store the partially completed model (created with Model.new) in a session. Only save it to the database when it is completely valid.
I am looking on trying to use acts_as_paranoid plugin for soft delete of records. I was earlier managing it using a flag in the db. I know that this plugin will omit a record from searches and finds if the record is soft deleted. What I want to know is if I have a validation in the model like validates_uniqueness_of :email and I deleted(soft deleted) the record having email 'prince#gmail.com'. Now when I try to create a new user having same email, will the validation work and prevents the creation of the new record. Or will it omit the soft deleted record as it does for finds? (I would like this to happen, of course.)
acts_as_paranoid does not reimplement validates_uniqueness_of, so if you have (soft) deleted a record with email 'prince#gmail.com' you cannot create a new record with the same email.
The easy fix for this is to add a scope to validates_uniqueness_of:
validates_uniqueness_of :email, :scope => :deleted_at
This way you can have any number of (soft) deleted records with email 'prince#gmail.com' and still create a new record with the same email.
From our testing, the patching that acts_as_paranoid does affect the deletes, so you would end up with two records. From most of the conversations around the web, this is probably what you expect.
In our case, we didn't want this. When we create another user with the same email, we want to "undelete" the first user, and we'd like the validations to hep us with this. Turns out that we couldn't figure out a way to do what we wanted. We ended up not using acts_as_paranoid in this case, but we are still considering going back.
We did find one patch that allowed passing in a flag to validations (:with_deleted => true), so that you could explicitly control this. This seems like a good idea, but we decided not to pursue it. Unfortunately this issue highlights that this approach is a bit of a "leaky abstraction" and has to be used with care.
if yor are using "rails3_acts_as_paranoid" then have provision for above mentioned issue,
ActiveRecord's built-in uniqueness validation does not account for records deleted by ActsAsParanoid. If you want to check for uniqueness among non-deleted records only, use the macro validates_as_paranoid in your model. Then, instead of using validates_uniqueness_of, use validates_uniqueness_of_without_deleted. This will keep deleted records from counting against the uniqueness check.
Need to specify following way ,
acts_as_paranoid
validates_as_paranoid
validates_uniqueness_of_without_deleted :name
Given a model that has validations in the model_name.rb file, how can I access those validations manually? I'd like to cook up my own form validation system that would work alongside the built-in Rails tricks and I want to keep everything as DRY as possible. My main problem is that I need to make server-side validations before any of the form values hit the database (I'm using a multistep form).
Basically I'm wondering if there is a method like
User.validations.each do |v|
puts v.constraint.to_s + " " + v.message
end
Is there anything similar to this?
Thanks in advance.
My main problem is that I need to make
server-side validations before any of
the form values hit the database (I'm
using a multistep form).
If your model is not valid according to the validations in its class file, then its data won't get saved to the database (unless you pass false to the save method to suppress validations).
You can ask a model if it's valid at any point by invoking its valid?/invalid? methods.
The ActiveRecord object exposes the errors method after valid? is called, which gives you messages about which validations are violated. You could check valid? and then check to see if any of the fields on the part of the form you are on are invalid.
you could do something like this for a form with fields field1 and field2.
unless x.valid?
[:field1,:field2].each do |field|
yes_there_was_an_error if x.errors[field]
end
end
Your best bet is to use a state machine and store the data in the database between the various steps in the form.
You can do e.g. validates_presence_of :username, :if => proc {|u| u.signup_step >= 2 }, where signup_step is an integer column in the database.
So, even though you say you don't want to store it in the database between the forms, I think you should. If you do this, you can use regular validations and models, without nasty hacks. And honestly, I doubt doing it this way is a problem.