Rails 5: custom slugs for rails urls error - ruby-on-rails

I was following the tutorial on hackernoon, to generate Obfuscated URLs.
The first step is to add a slug column to the database, but I got an error.
AddSlugToReservations
class AddSlugToReservation < ActiveRecord::Migration[5.2]
def change
add_column :reservations, :slug, :string, null: false
add_index :reservations, :slug, unique: true
end
end
I get the following error when I try rails db:migrate
SQLite3::SQLException: Cannot add a NOT NULL column with default value NULL: ALTER TABLE "reservations" ADD "slug" varchar NOT NULL
So I change the migration file to:
class AddSlugToReservation < ActiveRecord::Migration[5.2]
def change
add_column :reservations, :slug, :string, null: false, default: 0
change_column :reservations, :slug, :string, default: nil
add_index :reservations, :slug, unique: true
end
end
But then I encountered the following error:
SQLite3::ConstraintException: UNIQUE constraint failed: reservations.slug: CREATE UNIQUE INDEX "index_reservations_on_slug" ON "reservations" ("slug")
What should I do? I couldn't find any solution to this...

You can do this with below code
class AddSlugToReservation < ActiveRecord::Migration[5.0]
def change
add_column :reservations, :slug, :string, unique: true, default: 0, null: false
end
end

try this
class AddSlugToReservation < ActiveRecord::Migration[5.2]
def change
add_column :reservations, :slug, :string, unique: true
change_column_null :reservations, :slug, false
end
end
Hope it helps.

Related

"rails db:migrate" error : relation "users" does not exist?

I am newbie with rails and here is my problem.
I created a very simple rails program and in the db > migrate > 2023.._add_columns_to_user.rb file, I added this code to this file
class AddColumnsToUser < ActiveRecord::Migration[7.0]
def change
add_column :users, :full_name, :string
add_column :users, :from, :string
add_column :users, :about, :text
add_column :users, :language, :string
add_column :users, :status, :boolean
add_column :users, :status, :boolean, default: false
end
end
Then I ran this code
rails db:migrate
But it gave me this error
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "users" does not exist
May be I must create the database first?
Could you please give me some advices for this problem?
Here is all of my code, if you need for reference.
https://github.com/nguyencuc2586/Addcustomfieldsoutusermodel
Thank you in advance.
You can't alter a table that hasn't yet been created. Your migration should be wrapped in a table defintion:
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :full_name # shorthand for add_column :users, :full_name, :string
t.string :from
t.text :about
t.boolean :status, default: false # why on earth is this a boolean?
t.timestamps
end
end
end
This results in CREATE TABLE users (...) while your migration would result in ALTER TABLE users (...).

How to drop a fk constraint in production

I have the following situation in production:
My PersonalInfo model was created using t.references :user, foreign_key: true, index: true, unique: true to model Users. However, PersonalInfo became polymorfic, with this migration:
class AddInfoOwnerToPersonalInfos < ActiveRecord::Migration[5.1]
def up
rename_column :personal_infos, :user_id, :info_owner_id
add_column :personal_infos, :info_owner_type, :string
add_index :personal_infos, [ :info_owner_type, :info_owner_id]
PersonalInfo.update_all(info_owner_type: 'User')
change_column :personal_infos, :info_owner_type, :string, null: false
end
def down
rename_column :personal_infos, :info_owner_id, :user_id
remove_column :personal_infos, :info_owner_type
end
end
The problem:
Still remain a fk constraint in database:
ALTER TABLE ONLY public.personal_infos
ADD CONSTRAINT fk_rails_796da13f22 FOREIGN KEY (info_owner_id) REFERENCES public.users(id);
How could I build a migration to remove safely this constraint? (I believe no constraint is needed in polymorphic associations, only the index)
if foreign_key_exists?(:personal_infos, :users)
remove_foreign_key(:personal_infos, :users)
end
See:
Rails API: remove_foreign_key

Default rails id column name in Rails

I wanna rename the column id, how do I do?
I want to set number to primary key and auto increment, and id to just string of user id.
How do I do?
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :user
t.timestamps
end
rename_column :users, :id, :number
end
end
I did like above, but it didn't work.
Even if I wouldn't recommend it, here is how I guess you can do it:
in your migration:
def up
create_table :users, id: false do |t|
t.string :user
t.integer :number, null: false, index: true, unique: true
t.timestamps
end
execute %Q{ ALTER TABLE "users" ADD PRIMARY KEY ("number"); }
end
def down
drop_table :users
end
in your model:
self.primay_key = 'number'

Add data to a unique, required column

I'm looking for the preferred way, and unique column to an existing table. I also want to add a unique index to the table. Before adding the index though, I obviously need to add data to the column to prevent the index creation from failing.
Here is the situation:
class AddUsernameToUsers < ActiveRecord::Migration
def change
add_column :users, :username, :string, null: false
# Need Data here! And don't want to do something like this:
# User.each { |u| u.update_attribute(:username, u.email }
add_index :users, :username, unique: true
end
end
I know using ruby code to populate the data is possible, there are lots of examples of that, but I keep reading that it isn't such a good idea. Are there any options other than something similar to the above?
would the following work for your situation?
class AddUsernameToUsers < ActiveRecord::Migration
def change
add_column :users, :username, :string, null: true
execute("UPDATE users SET username = email")
change_column :users, :username, :string, null: false
add_index :users, :username, unique: true
end
end

Adding unique: true for add_column and add_index in Active Record

Even though my application isn't gonna allow a user to key in a location, I wanted to enforce a uniqueness on city in the database. Since my Rails app will be searching on the city column, I would like to add an index on the city column as well but was wondering if it matters adding unique: true on the index as well. Is this repetitive? If this doesn't make sense, I would really appreciate it if you could explain why.
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :city, unique: true
t.string :state
t.timestamps
end
add_index :locations, :city, unique: true
end
end
Using Rails 4, you can provide: index param a hash argument
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :city, index: {unique: true}
t.string :state
t.timestamps
end
end
end
As far as I know the unique option in the create_table block is actually not supported and doesn't do anything, see TableDefinition. To create the unique index, you need to call the method add_index the way you do now. Note that a unique index is both for uniqueness and for searching etc., there's no need to add two indexes on the same column.
You can specify unique index while scaffolding:
rails generate model Locations city:string:uniq state:string
This will create Model, Spec, Factory and this migration:
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :city
t.string :state
t.timestamps null: false
end
add_index :locations, :city, unique: true
end
end
Rails knows what it's doing - nothing more is required.
Add: index: { unique: true }
Example:
class AddUsernameToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :username, :string, null: false, index: { unique: true }
end
end

Resources