How to rename fields and make them not nulls - ruby-on-rails

My current schema looks like:
create_table "users", :force => true do |t|
t.string "username"
t.string "firstname"
t.string "lastname"
t.datetime "loggedin_at"
t.datetime "created_at"
t.datetime "updated_at"
t.integer `user_status`
end
I want to rename username to user_name, and make all the fields not null (they are currently nullable).
How would I do this? Do I create a migration file using rails generate, and then have to tweak it manually? How so?

It can help if you specify the Rails version number.
Before 3.0, it is:
Rails: How can I rename a database column in a Ruby on Rails migration?
If it is 3.0 or later, then you can look at the Migration documentation, such as rails generate instead of script/generate.

Related

rails migration generating random tables. Where is this coming from?

When I run rails db:migrate without a new migration it seems to have added two new tables: questions and questions_1.
In my schema file I see:
create_table "questions", id: false, force: :cascade do |t|
t.integer "id"
t.text "text"
t.boolean "active"
t.integer "organization_id"
t.datetime "created_at"
t.datetime "updated_at"
t.bigint "account_id"
t.bigint "team_id"
end
create_table "questions_1", id: false, force: :cascade do |t|
t.integer "id"
t.text "text"
t.boolean "active"
t.integer "organization_id"
t.datetime "created_at"
t.datetime "updated_at"
t.bigint "account_id"
t.bigint "team_id"
end
I don't have any migrations making these tables. I'm guessing this is some sort of convention. Where do I look to fix this? All recent changes are in the app/ directory and a migration I made has been rolled back and then deleted. Yet when I run rails db:migrate I always get these new tables.
Any ideas?
Rails won't create tables with any name other than the ones specified in a migration. If the table already exists then it will throw an error.
I believe someone has run a migration creating the second table on your database, and then deleted the migration. When rails creates your schema.rb file, it uses your database rather than any migrations, meaning this file reflects your actual database state rather than the one your migrations suggest would be the case.
If you're sure you don't want the second table and it has no data in it, then you can write out a new migration to delete this table, run it, and then delete it. This will return your database state to the one your migrations suggest would be the case. You can then run rake db:schema:dump to update your schema.

Migrating legacy data to new model in rails

I'm getting started with Rails again and am running into a conundrum I find intimidating at the moment. I'm somewhat of a noob when it comes to working with databases, so please forgive me if this is fairly basic.
I have an older Rails app with a data model I no longer wish to conform to. The model should be deprecated in favor of a lighter, less complex one.
The older app is also very monolithic, so I'm trying to break it up into smaller service components.
So this leads me to my question, since it's generally frowned upon to use multiple databases from a single model… what would be the best method for translating data stored in the old model to my new model, one service at a time?
For example, let us suppose I have a user model in both the old and the new. In the old model, the user has many columns, not all of which should make it to the new model.
An example of this could be a change from a user being limited to a single address in the old model to being able to assign a one to many relationship where addresses are split off in their own model and simply referenced using a foreign key or something.
EDIT 1:
The goal ultimately is to siphon the data from the legacy model's database into the new model's database as easily as possible, one dataset at a time.
EDIT 2:
Originally posted from my mobile. Here are a couple examples which may help with suggestions.
OLD MODEL
create_table "brands", force: :cascade do |t|
t.string "name"
t.string "url"
t.string "logo"
t.boolean "verified"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "hidden", default: false
t.string "facebook_url"
t.string "twitter_handle"
t.string "pinterest_handle"
t.string "google_plus_url"
t.string "address_street1"
t.string "address_street2"
t.string "address_street3"
t.string "address_city"
t.string "address_state"
t.string "address_zip"
t.string "address_country"
t.string "email"
t.string "phone"
t.string "story_title"
t.text "story_text"
t.string "story_photo"
end
NEW MODEL
create_table "companies", force: :cascade do |t|
t.string "companyName", null: false
t.string "companyURL", null: false
t.boolean "companyIsActive", default: true, null: false
t.boolean "companyDataIsVerified", default: false, null: false
t.string "companyLogoFileURL"
t.datetime "companyFoundedOnDate"
t.integer "companyHQLocationID"
t.integer "companyParentCompanyID"
t.integer "companyFirstSuggestedByID"
t.string "companyFacebookURL"
t.string "companyGooglePlusURL"
t.string "companyInstagramURL"
t.string "companyPinterestURL"
t.string "companyTwitterURL"
t.string "companyStoryTitle"
t.text "companyStoryContent"
t.string "companyStoryImageFileURL"
t.boolean "companyIsHiddenFromIndex", default: false, null: false
t.integer "companyDataScraperID"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
So, basically... I want to be able to take data from the old model, say a brands "name" column and siphon its related values to the new model so the value ends up in the companies "companyName" column of a totally different postgresql instance.
Having done this multiple times, I can tell you that the easiest thing to do is to create a simple rake task that iterates the first collection and creates items in the new collection.
There is no need to use anything like DataMapper. You already have ActiveRecord and can simply define which DB connection to use for each model.
In your config/database.yml:
brand_database:
adapter: postgresql
host: brand_host
username: brand_user
password: brand_pass
database: brand_db
company_database:
adapter: postgresql
host: company_host
username: company_user
password: company_pass
database: company_db
In your models:
class Brand < ActiveRecord::Base
establish_connection :brand_database
end
class Company < ActiveRecord::Base
establish_connection :company_database
end
In your new rake task (lib/tasks/db.rake):
# lib/tasks/db.rake
namespace :db do
desc "Migrate brand records to company records"
task :migrate_brands_to_companies, [] => :environment do
Brand.find_each do |brand|
Company.find_or_initialize_by(companyName: brand.name) do |company|
puts "\n\tCreating Company record for #{brand.name}"
company.companyURL = brand.url
company.companyLogoFileURL = brand.logo
company.companyTwitterURL = "https://twitter.com/#{brand.twitter_handle}"
company.companyIsHiddenFromIndex = brand.hidden
company.created_at = brand.created_at
company.updated_at = brand.updated_at
company.save!
end
end
end
end
Finally, run the rake task:
$ rake db:migrate_brands_to_companies
I need to say this: Rails is built using a solid convention. Failing to adhere to that convention will cause problems and additional expense, everytime. I have seen this many many times. Every single time I have seen someone deviate from that convention, they run into far more trouble than they would have ever expected. They break a lot of the "Rails magic".
Taking a TDD approach would certainly help you cover more ground.
Look at DataMapper, which you can use in a Rake task or completely separate Ruby-script. This way, you can iterate over the app data (from Active Record) and pass it to the new Postgres DB via DataMapper.
You can connect to the new DB like this,
DataMapper.setup(:default, 'postgres://user:password#hostname/database')

Adding column to books table in rails

how am i able to add a column to my books table in rails? i want to do this through a migration
This is my schema:
ActiveRecord::Schema.define(version: 20160716030811) do
create_table "books", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
You do this by running a migration. It depends on what column you want to add. I see you have a name column already, so if you were to create a description column, run rails generate migration AddDescriptionToBooks description:string
If you want to create a different column just replace the 2 description words in that migration code with whatever you want
This will create a migration which adds a column description to the table.

Remove Tables from Schema

This is probably a fairly basic question, but I'm at a loss on how to clean up after installing a gem I decided not to use. During the install process of Attachinary, the install instructions said to run rake attachinary:install:migrations - creating a new table and index in my schema, noted here:
create_table "attachinary_files", force: :cascade do |t|
t.integer "attachinariable_id"
t.string "attachinariable_type"
t.string "scope"
t.string "public_id"
t.string "version"
t.integer "width"
t.integer "height"
t.string "format"
t.string "resource_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "attachinary_files", ["attachinariable_type", "attachinariable_id", "scope"], name: "by_scoped_parent", using: :btree
I later decided to go with a simplier attachement gem and I'm attempting to clean up and remove all the "stuff" created during the attachinary install.
Any advice on how to clean up the db? I'm running Postgresql if that makes any difference.
Create a migration:
bundle exec rails g migration remove_attachinary
Then tell Rails what to do:
def up
drop_table :attachinary_files
end
Remove the change method present by default
If ever you'd like this migration to be reversible, copy your previous code in a down method

Data migrations for older version of friendly id

I'm migrating a very old app from friendly_id 3.2 to 5.1.
I have a user model which currently has a cached_slug field. I created a new field called just slug. Initially, I thought I could just copy the data over from cached_slug to slug, but I noticed that there's also a whole other table called slugs which looks like this:
create_table "slugs", force: :cascade do |t|
t.string "name", limit: 255
t.integer "sluggable_id"
t.integer "sequence", default: 1, null: false
t.string "sluggable_type", limit: 40
t.string "scope", limit: 255
t.datetime "created_at"
end
Following the directions in the FriendlyID README for the Rails Quickstart, I ran rails generate friendly_id which created this table:
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
end
So now I'm all confused about what I need to do to complete migration. I tried creating a new user with the console and the friendly_id_slugs table is still empty, so I'm not sure when or what it's used for.
I have two questions:
1) What is this other table used for
2) What do I need to do to migrate my old slugs to the new table/field so it will continue to work moving forward?
Thanks!
If you don't mind losing the FriendlyId's History records (i.e: the old slugs),
drop the old slug table
in the rails console, run <ModelName>.find_each(&:save) for all friendly_id models.
Step 2 should regenerate new slugs.
Warning: Test before doing this on production servers!
Update: You can also perform step 2 in a migration file
class RegenerateSlugs < ActiveRecord::Migration
def change
# <ModelName>.find_each(&:save)
User.find_each(&:save)
Article.find_each(&:save)
end
end

Resources