Retroactively adding the primary key to a table - ruby-on-rails

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

Related

Why does setting a default value for an existing column in an ActiveRecord Migration not extend to existing associations on production?

If I add a default value to an existing column through an ActiveRecord Migration, when deploying my changes to production, existing associations are not affected.
I can drop to a rails production console and iterate over every single record and set the value on the new column to false on each record however it's tedious and doesn't scale well.
class AddDefaultValuesToAFewColumns < ActiveRecord::Migration[5.2]
def change
change_column :downloads, :is_deleted, :boolean, :default => false
end
end
create_table "downloads", force: :cascade do |t|
t.string "version"
t.string "comment"
t.string "contributors"
t.string "release_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "download_url"
t.boolean "is_deleted", default: false
end
The expected result would be for associations when queried from the rails console to return false for is_deleted, rather it returns nil. Why is this and what alternative solutions are there?
That's how it works. When you change the column default value, you are configuring the default value for new records, not existing ones. If you want to update existing values with false then do something like Download.where(is_deleted: nil).update_all(is_deleted: false) right after the change_column line:
class AddDefaultValuesToAFewColumns < ActiveRecord::Migration[5.2]
def change
change_column :downloads, :is_deleted, :boolean, :default => false
Download.where(is_deleted: nil).update_all(is_deleted: false)
end
end

how do you enforce uniqueness in ruby on rails migration? [duplicate]

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

Unable to create a record because join table requires created_at (HABTM + Rails)

Googling for this, I see the Rails core team is working on a solution for Rails 4 but that's a ways away.
Both Users and Circles have a has_and_belongs_to_many relationship to the other.
My schema looks like this:
create_table "circles", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "circles_users", :force => true do |t|
t.integer "circle_id"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
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"
end
But in my code, in my circles_controller when I try to do this:
def create
#circle = Circle.new(params[:circle])
#circle.users << User.find(session[:user].id)
...
I get the following error in my browser:
SQLite3::ConstraintException: circles_users.created_at may not be NULL: INSERT INTO "circles_users" ("circle_id", "user_id") VALUES (11, 5)
What should I do about created_at and updated_at being false here?
I ended up getting it to work by removing the timestamps from the migration that was used to create the join table.
The right schema should be like this:
create_table "circles_users", :force => true do |t|
t.integer "circle_id"
t.integer "user_id"
end
try this
def new
#circle = Circle.new
1.times { #circle.users.build } if #circle.users.nil?
end
def create
#circle = Circle.new(params[:circle])
#circle.update_attributes(session[:user]) # this will automatically update location table by using relationship
#circle.save
end
see HABTM
Just give this a try
def create
#circle = Circle.new(params[:circle])
#circle.users = [User.find(session[:user].id)]
Might not work, I have not tried it locally, sry abt that ^_^
In these datetime fields you should insert current timestamp or change them to nullable fields if you not filling them with data.

unknown attribute: user_id

I'm getting the error unknown attribute: user_id durring execution of current_user.stories.build
class User < ActiveRecord::Base
has_many :stories, class_name: 'Story', foreign_key: 'user_id', dependent: :destroy
...
class Story < ActiveRecord::Base
belongs_to :user, class_name: 'User', foreign_key: 'user_id'
...
schema.rb
create_table "stories", :force => true do |t|
t.string "responsible"
t.string "descr"
t.string "state"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "email"
t.string "password_digest"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "name"
end
It doesn't contain 'user_id' field. Any ideas?
Kulbir is correct that you need to define a user_id column in your stories table, but doesn't explain the way to do that.
The correct way to make that change is to create a new migration. By convention, it should be called add_user_id_to_stories and would be created as follows (assuming you're using Rails 3+):
rails generate migration add_user_id_to_stories
If you run that, it should actually generate a migration that already contains the change you need to make, which should be something like:
add_column :stories, :user_id, :integer
As an aside when you're following the Rails conventions concerning association naming, which you are, you can actually skip a lot of the extra specification. In the User model, you can specify just has_many :stories and in the Story model specify belongs_to :user. Rails will assume the same class names and foreign keys you've specified.
You should have a user_id field in your stories table like below to define the association in your models.
create_table "stories", :force => true do |t|
t.integer "user_id"
t.string "responsible"
t.string "descr"
t.string "state"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
...
end
Edit
Check Emily's answer for detailed explanation.
you should use the new syntax and pass the fieldtype as symbol
add_column :stories, :user_id, :integer

Entrys aren't being saved to my database correctly?

Here's my schema file..
ActiveRecord::Schema.define(:version => 20120505115340) do
create_table "clients", :force => true do |t|
t.string "name"
t.string "detail"
t.string "more_detail"
t.string "more_details"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "jobs", :force => true do |t|
t.string "name"
t.integer "number"
t.string "responsible"
t.string "monthly"
t.string "quarterly"
t.string "other"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
And here's my migration file's..
class CreateClients < ActiveRecord::Migration
def change
create_table :clients do |t|
t.string :name
t.string :detail
t.string :more_detail
t.string :more_details
t.timestamps
end
end
end
class CreateJobs < ActiveRecord::Migration
def change
create_table :jobs do |t|
t.string :name
t.integer :number
t.string :responsible
t.string :monthly
t.string :quarterly
t.string :other
t.timestamps
end
end
end
In my view file, I have it setup so that is pulls out the client.name and shows it to the user <%= link_to client.name, client_path(client) %>.
However, all im getting back when I create a new entry is /clients/1 instead of the name that I specified in my form.
When I try to migrate the DB nothing happens and then when I try to drop he DB to start afresh it tells me that it does even exist.
If I understand you correctly, you are concerned that your view displays a link to /clients/1 for your newly created object?
This is the default path when using Ruby on Rails, and is what will be produced by the path helper object_path(object) that you are using. This can be customized (see guides on routes.rb). If this is not a problem, then your application is working as intended.
BtW, the number used in the default path refers to the id given to the object. All objects stored using ActiveRecord will automatically get a unique id which can be used to identify the object. Just as the created_at and updated_at columns in your schema, the id column will be created regardless if you explicitly define it in your schema or not.
To reset your database (drop, recreate and migrate to current schema), use the following command:
rake db:reset
EDIT:
<%= link_to client.name, client_path(client) %>
Should result in the following HTML (where CLIENT_NAME is the name attribute of the client)
CLIENT_NAME

Resources