This question already has answers here:
A migration to add unique constraint to a combination of columns
(6 answers)
Closed 7 years ago.
Based off http://guides.rubyonrails.org/v3.2.21/migrations.html and
given the following migration:
class CreateVacations < ActiveRecord::Migration
def change
create_table :vacations do |t|
t.string :name
t.string :slug, :uniqueness => true
t.datetime :starts_at
t.datetime :ends_at
t.timestamps
end
end
end
I ran rake db:migrate and see this schema:
ActiveRecord::Schema.define(:version => 20150825170615) do
create_table "vacations", :force => true do |t|
t.string "name"
t.string "slug"
t.datetime "starts_at"
t.datetime "ends_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
I do not ssee any uniqueness requirement for 'slug'. If I did it wrong, how can I fix it at this point?
If it was right, why doesn't the schema say it's unique? Thank you
You need to create an index in order to enforce uniqueness at the database level:
add_index :vacations, :slug, unique: true
Related
I'm trying to add validation at the database level. For the model file it was no problem but now for the migration file, I just don't get how to do this. I am using SQLite for development (following Hartl's tutorial but adapting the instructions for my own app).
I have the two following migration files:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email, null: false
t.string :email_confirm, null: false
t.string :username, null: false
t.text :bio
t.string :location, null: false
t.boolean :activated, default: false
t.datetime :activated_at
t.timestamps null: false
end
end
end
and:
class AddIndexToUsersEmailAndUsername < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
add_index :users, :username, unique: true
end
end
But the validations do not end up in schema.rb:
ActiveRecord::Schema.define(version: 20150410200022) do
create_table "Users", force: :cascade do |t|
t.string "email"
t.string "email_confirm"
t.string "username"
t.text "bio"
t.string "location"
t.boolean "activated"
t.datetime "activated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["username"], name: "index_users_on_username", unique: true
end
So null:false and default:false are not in schema.rb and apparantly Rails is not implementing these validations. How should I implement these validations in the migration file?
I've also tried using change_column_null and change_column_default instead but with the same result/schema.rb.
Rails does let you provide null and default options to columns in migrations.
After editing the user migration file, have you rerun it?
You can do a rake db:rollback followed by a rake db:migrate
If you had run CreateUsers and AddIndexToUsersEmailAndUsername for last, You should do a rollback with two steps like rake db:rollback STEP=2
rails not null / unique in migrations doesn't trigger error :S
class CreateDeditProjects < ActiveRecord::Migration
def change
create_table :dedit_projects do |t|
t.string :name, :null => false
t.string :uid, :unique => true
t.boolean :status
t.timestamps null: false
end
end
end
empty name doesn't trigger error. Neither does duplication of uid.
This is what I see in schema.db
ActiveRecord::Schema.define(version: 20150410105216) do
create_table "dedit_projects", force: :cascade do |t|
t.string "name", null: false
t.string "uid"
t.boolean "status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
hm, I need to add indexes somewhere I guess? Shouldn't that be automatic?
Not null problem is bogus though.
Rails automatically adds index on id and references and maybe on some other types. If You want to add new index, You can create a migration:
def change
add_index :dedit_projects, :uid, unique: true
end
You can also use validations validates_uniqueness_of and validates_presence_of in models. Although I don't understand why doesn't it work as it is :)
Uniqueness is a property of the index so you need either a separate call to add_index or write it like so
create_table :dedit_projects do |t|
t.string :uid, index: {unique: true}
...
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I know there are quite a few questions on this topic here on SO but none of them seem to be the solution for my case. So, I was hoping someone might be able to help.
When I run a migration I get the following error:
CreateEvents: migrating
-- create_table(:events)
-> 0.0558s
-- add_index(:events)
rake aborted!
An error has occurred, this and all later migrations canceled:
wrong number of arguments (1 for 2)
I don't know exactly what I'm looking for and where. I wanted to change my Users table to a Registrations table.
Registrations Controller:
class RegistrationsController < ApplicationController
end
Registration Model:
class Registration < ActiveRecord::Base
attr_accessible :email, :password_digest
end
Registration Migration:
class CreateRegistrations < ActiveRecord::Migration
def change
create_table :registrations do |t|
t.string :email
t.string :password_digest
t.timestamps
end
end
end
Schema.rb:
ActiveRecord::Schema.define(:version => 20130825195829) do
create_table "activities", :force => true do |t|
t.integer "trackable_id"
t.string "trackable_type"
t.integer "owner_id"
t.string "owner_type"
t.string "key"
t.text "parameters"
t.integer "recipient_id"
t.string "recipient_type"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "activities", ["owner_id", "owner_type"], :name => "index_activities_on_owner_id_and_owner_type"
add_index "activities", ["recipient_id", "recipient_type"], :name => "index_activities_on_recipient_id_and_recipient_type"
add_index "activities", ["trackable_id", "trackable_type"], :name => "index_activities_on_trackable_id_and_trackable_type"
create_table "comments", :force => true do |t|
t.string "commenter"
t.text "body"
t.integer "event_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "comments", ["event_id"], :name => "index_comments_on_event_id"
create_table "events", :force => true do |t|
t.string "title"
t.text "text"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
add_index needs 2 arguments example: add_index :events, :title
I wrote a migration for a join model which looks like:
create_table "project_memberships", :id => false, :force => true do |t|
t.integer "user_id"
t.integer "project_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "id"
end
I want to forcibly create ids now. Must I drop the table and recreate it or can I write a migration removing this constraint?
With a small amount of googling... http://thinkwhere.wordpress.com/2009/05/09/adding-a-primary-key-id-to-table-in-rails/
Generate a empty migration:
rails generate migration AddIdToProjectMemberships
and fill it in with:
def change
add_column :project_memberships, :id, :primary_key
end
Also there was a question like this before.. how to add a primary key to a table in rails
I am creating a forum software. I want admins and mods to be able to close certain topics.
Codes are sanitized to show only relevant info.
Models
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :bio
has_many :topics, dependent: :destroy
end
class Topic < ActiveRecord::Base
belongs_to :user
attr_accessible :name, :last_post_id, :content
end
Schema for user: admin and mod columns determine admins and mods.
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
t.boolean "admin", :default => false
t.text "bio"
t.boolean "mod", :default => false
end
Schema for topic: closed column determines topic's closed status.
create_table "topics", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "forum_id"
t.string "name"
t.integer "last_post_id"
t.integer "views"
t.integer "user_id"
t.boolean "closed", :default => false
t.text "content"
end
I am reluctant to user attr_accessible :closed for TOPIC model because it will be vulnerable to malicious PUT request (correct me if I am wrong).
Is there some way for Rails app to be able to access and modify value of closed column of TOPIC without using attr_accessible, so that only mods and admins can edit them?
I searched on google and found this ascii cast.
Basically, you are looking for dynamic attr_accessible.
If you currently have
class Article < ActiveRecord::Base
attr_accessible :name, :content, :closed
end
You ca use dynamic attr_accessible like this :
class Article < ActiveRecord::Base
attr_accessible :name, :content
private
def mass_assignment_authorizer
super + [:closed]
end
end
I hope I is what you are looking for.
Be sure to check the link I gave you for complete reference.