Uniqueness of a pair of attributes not working - ruby-on-rails-3

I have a User model that has among other things an email and a university_id
I have added the following line to my model file:
validates_uniqueness_of :email, :scope => [:university_id]
but when I try to create a user with a same email but a different university_id I get the following error message:
ActiveRecord::RecordNotUnique in UsersController#create
SQLite3::ConstraintException: column email is not unique: INSERT INTO "users" ("name", "email", "password", "created_at", "updated_at", "university_id") VALUES ('my name', 'myusername', 'asdfgh', '2012-08-12 04:31:39.135115', '2012-08-12 04:31:39.135115', 2)
I know email is not unique, but the pair email, university_id is, so why am I getting this exception and how can I fix it?
Thanks!

If you have a uniqueness constraint in your db, it can conflict with ActiveRecord's uniqueness constraint. Check your migrations and remove the constraint if it exists.

Related

What does "null: false" really do?

I recently created a rails migration to add a Username to my devise Users.
add_column :users, :username, :string
I created a test account and signed up without entering a username. The registration went through and created a user with no user name. I had to fix this since I need a username to set the profile url. So I updated my migration to:
add_column :users, :username, :string, null: false
I thought this would prevent a user from creating a account with a null username - didn't work! I was still about to register with no username.
Eventually adding...
validates_presence_of :username
...to my user.rb model fixed the issue. But why didn't null:false stop it? Why should I keep it and how does it work?
This statement:
add_column :users, :username, :string, null: false
translates exactly to SQL DDL (Data Definition Language) standard:
ALTER TABLE users ADD username VARCHAR(255) NOT NULL;
The trailing NOT NULL is effect of null: false. You can use other column modifiers which some of them are directly translated into DDL.
Remember that if you already apply the migration to the database the further modifications should be done with a new migration file. Updates to migration Ruby files are not propagated to database schema when the migration was already applied. Eventually you can rollback last migrations and rerun them but then you may loose existing data during the schema rollback. See Changing Existing Migrations

Automatic ID generation with create! block in model

I'm trying to use the following inside my model:
create!(
:title => entry.title,
:link => entry.url,
:published_date => entry.published,
:entry_id => entry.id,
:category => thing,
:author => entry.author,
:user_id => user.id
)
This fails with Mysql2::Error: Duplicate entry '0' for key 'PRIMARY' when adding anything past the first entry since the id column is being set as 0. Is there a way to auto-increment the id using the above code?
Thanks
You should never need to manually specify the ID when creating new instances; Rails will automatically create the auto-incrementing column to handle generating unique IDs for you.
In this case, if you have tampered with the ID column and changed its type, the easiest way to reset this is to simply recreate the table.

rails activerecord _id suffix in property

What is the implication of using a "_id" suffix for a field name in active record?
t.string :foo_id
Does this always presume that it is a foreign key to "foo" table?
Is it better to use something like
t.string :foo_id_value
to avoid ambiguity with rails?
The idea is that this id value has nothing to do with foreign keys and may not necessarily be unique.
You may wind up with a strange validation message.
Given a Rails 3 model with a validation like validates :foo_id, :presence => true,
when you leave foo_id blank and validate,
then you'll get the message "Foo can't be blank" instead of the expected "Foo id can't be blank".
It's a matter of convention. In my experience you won't have any problems unless you do belongs_to :foo
If you want to avoid ambiguity for other developers, then yes, it's a good idea to avoid it.

paper_trail gives me errors with existing User model

Is there any conflict to set a User model to be versioned with paper_trail? I have a model 'User' as follows:
class User < ActiveRecord::Base
has_paper_trail
end
The problem is that whenever I call user#versions I get an exception:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'versions.user_id' in 'where clause': SELECT `versions`.* FROM `versions` WHERE (`versions`.user_id = 6)
(exception thrown when called versions on a User with id = 6.
I also have problem when I am trying to save a User. I get the following exception:
ActiveRecord::StatementInvalid: Mysql2::Error: Column 'item_id' cannot be null: INSERT INTO `versions` (`event`, `created_at`, `item_id`, `item_type`, `object`, `whodunnit`) VALUES ('update', '2011-11-17 10:38:43', NULL, NULL, '--- ....
which seems that save does not populate the item_id and item_type.
Any help would be much appreciated.
Thanks in advance
The problem was that I had also added has_many :versions in my User model and there was a conflict.
To avoid the conflict, I followed what the paper_trail mentions in the documentation:
has_paper_trail :versions => :paper_trail_versions

Unique on three different fields

I am working on a Ruby on Rails web application. I want to validate the uniqueness of more than one field together. How can i do this?
For example: I have a model named waiting with three fields:
project_id category_id and user_id
I want to ensure that i won't have two identical rows in all three fields.
Why not just to:
validates_uniqueness_of :user_id, :scope => [:project_id, :category_id]
+
add_index :waitings, [:project_id, :category_id, :user_id], :unique => true
Read API:
http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_index
It's not pretty but this works for me:
class Waiting < ActiveRecord::Base
validate :must_be_unique
def must_be_unique
if self.class.where(project_id: project_id, category_id: category_id, user_id: user_id).exists?
errors.add(:base, 'Must be unique')
end
end
end
Of course you could just use a unique key in your db schema and then catch the relevant exceptions on the rare occasion you need to.