Database not completely updated in rails migration - ruby-on-rails

I am new to Ruby on Rails. I have a migration called create user
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.column :username, :string, :limit => 25, :default => "", :null => false
t.column :hashed_password, :string, :limit => 40, :default => "", :null => false
t.column :first_name, :string, :limit => 25, :default => "", :null => false
t.column :last_name, :string, :limit => 40, :default => "", :null => false
t.column :email, :string, :limit => 50, :default => "", :null => false
t.column :display_name, :string, :limit => 25, :default => "", :null => false
t.column :user_level, :integer, :limit => 3, :default => 0, :null => false
end
User.create(:username=>'test',:hashed_password=>'test',:first_name=>'test',:last_name=>'test',:email=>'test#test.com',:display_name=> 'test',:user_level=>9)
end
end
When I run rake db:migrate the table is created with the columns as mentioned above but the test data are not there
mysql>select * from users;
Empty set (0.00 sec)
EDIT I just dropped the whole database and restarted the migration and now it is showing the following error.
rake aborted!
An error has occurred, all later migrations canceled:
Can't mass-assign protected attributes: username, hashed_password, first_name, last_name, email, display_name, user_level
What am I doing wrong please help?
Thank you.

add
attr_accessible :username, :hashed_password, :first_name, :last_name, :email, :display_name, :user_level
to your user.rb

That's Rails way of prohibiting users to create or update objects via a param hash. You need to specify your User attributes as attr_accessible in your model:
example :
class User
attr_accessible :username, :firstname (etc)
end
Read more about Mass Assignment here.

just to complete the answer about testing environment. You can run rake db:test:prepare to check the migrations and load schema !

Related

Why is my Rails DB migration not creating columns?

I'm trying to do a DB migration in Rails using PostgreSQL, but the resulting schema doesn't contain any of my table definitions. Is there something wrong with my syntax that I'm not seeing?
Here's an example of one of my migration files and the resulting schema file after I run "rake db:migrate".
Migration file:
class Fields < ActiveRecord::Migration[5.2]
def change
def up
create_table :fields do |t|
t.column :totalsalesprsn, :float, :limit => nil, :null => false
t.column :totaladmkspend, :float, :limit => nil, :null => false
t.column :totalsalescost, :float, :limit => nil, :null => false
t.column :miscsales, :float, :limit => nil, :null => false
t.column :numleads, :float, :limit => nil, :null => false
t.column :costleads, :float, :limit => nil, :null => false
t.column :totalsalescost2, :float, :limit => nil, :null => false
t.column :totalmarketspent, :float, :limit => nil, :null => false
t.column :numsales, :float, :limit => nil, :null => false
t.column :averagecost, :float, :limit => nil, :null => false
t.column :costpersale, :float, :limit => nil, :null => false
t.column :totalspending, :float, :limit => nil, :null => false
t.column :totalsalesdonate, :float, :limit => nil, :null => false
t.column :totalsales, :float, :limit => nil, :null => false
t.column :pototal, :float, :limit => nil, :null => false
t.column :posales, :float, :limit => nil, :null => false
t.column :form_id, :integer
t.column :created_at, :timestamp
end
end
def down
drop_table :fields
end
end
end
Schema file:
ActiveRecord::Schema.define(version: 2018_10_25_161515) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "fields", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "forms", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "tables", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Would it have something to do with my model files? I have no idea why it's doing this, and I can't post more code, because I would have to add more details to this post in order to avoid the warning that my question doesn't have enough details.
It's not creating columns because you are defining up and down inside the change method.
Try this
class Fields < ActiveRecord::Migration[5.2]
def up
create_table :fields do |t|
t.column :totalsalesprsn, :float, :limit => nil, :null => false
t.column :totaladmkspend, :float, :limit => nil, :null => false
t.column :totalsalescost, :float, :limit => nil, :null => false
t.column :miscsales, :float, :limit => nil, :null => false
t.column :numleads, :float, :limit => nil, :null => false
t.column :costleads, :float, :limit => nil, :null => false
t.column :totalsalescost2, :float, :limit => nil, :null => false
t.column :totalmarketspent, :float, :limit => nil, :null => false
t.column :numsales, :float, :limit => nil, :null => false
t.column :averagecost, :float, :limit => nil, :null => false
t.column :costpersale, :float, :limit => nil, :null => false
t.column :totalspending, :float, :limit => nil, :null => false
t.column :totalsalesdonate, :float, :limit => nil, :null => false
t.column :totalsales, :float, :limit => nil, :null => false
t.column :pototal, :float, :limit => nil, :null => false
t.column :posales, :float, :limit => nil, :null => false
t.column :form_id, :integer
t.column :created_at, :timestamp
end
end
def down
drop_table :fields
end
end
Please have a look at the documentation here on how to define migrations.
From the documentation
The change method is the primary way of writing migrations. It works for the majority of cases, where Active Record knows how to reverse the migration automatically.
So, alternatively you can define the migration as well by doing the following
class Fields < ActiveRecord::Migration[5.2]
def change
create_table :fields do |t|
t.column :totalsalesprsn, :float, :limit => nil, :null => false
t.column :totaladmkspend, :float, :limit => nil, :null => false
t.column :totalsalescost, :float, :limit => nil, :null => false
t.column :miscsales, :float, :limit => nil, :null => false
t.column :numleads, :float, :limit => nil, :null => false
t.column :costleads, :float, :limit => nil, :null => false
t.column :totalsalescost2, :float, :limit => nil, :null => false
t.column :totalmarketspent, :float, :limit => nil, :null => false
t.column :numsales, :float, :limit => nil, :null => false
t.column :averagecost, :float, :limit => nil, :null => false
t.column :costpersale, :float, :limit => nil, :null => false
t.column :totalspending, :float, :limit => nil, :null => false
t.column :totalsalesdonate, :float, :limit => nil, :null => false
t.column :totalsales, :float, :limit => nil, :null => false
t.column :pototal, :float, :limit => nil, :null => false
t.column :posales, :float, :limit => nil, :null => false
t.column :form_id, :integer
t.column :created_at, :timestamp
end
end
end
you have your syntax somewhat wrong:
class Fields < ActiveRecord::Migration[5.2]
def change
def up
# your table definition
end
end
def down
# delete your table
end
end
Rails is smart enough to know that the reverse of creating a table is deleting it, so you don't need to specify def down.
You don't seem to show errors on the migration, so before doing the following, run the command rails db:rollback from your console
Then change your migration file to the following and run again rails db:migrate:
class Fields < ActiveRecord::Migration[5.2]
def change
# your table definition
end
end
Other answers here are correct. However if you already ran the migration and got no error, you will likely need to roll it back, but if that fails you will need to manually rollback the migration in the database. Because any migration will increment the schema_migrations with the version number in the migration filename.
So if your migration filename is something like 20181023191125_fields.rb you'll need to do this:
rails dbconsole
#now you should be in a (pg?) console
DELETE from schema_migrations WHERE version = 20181023191125;
\q # to quit postgres
But if this is a new project and you have seeds, it might be easier to just start over with a fresh database after fixing your migration as others have already instructed you.
ONLY DO THIS IF YOU ARE FINE WITH KILLING YOUR DB and STARTING OVER!!
rake db:setup
# or
rails db:setup
See Difference between rake db:migrate db:reset and db:schema:load

Rails change_column migration

I have this inside create_table:
t.string 'email', :default => '', :null => false
And then in another migration have this:
change_column('admin_users', 'email', :string, :limit => 100)
After I run everything, in schema.rb I get this:
t.string "email", limit: 100, default: "", null: false
Wasn't change_column supposed to overwrite everything in the previous definition? Why did :default and null were left? I was watching a tutorial where it said change_column overwrites everything. Was there some recent Rails version when this was changed?
Not necessarily, change_column does not erase previously-set details. Let's say you were changing the column so you could simply add a NULL constraint. It wouldn't make sense to have to add in all the other previously-set contraints as well.
If you want to change the default or null settings, just do so in the change_column method.
change_column('admin_users', 'email', :string, :limit => 100, :default => "", :null => true)
Otherwise, to erase everything, do remove_column then add_column:
remove_column('admin_users', 'email')
add_column('admin_users', 'email', :string, :limit => 100)
change_column doesn't overwrite everything, it just makes the changes you specify. So it added the limit to the column, but that's all.

add column to mailboxer migration

I wanted to add two columns to the migration that makes the notifications for the mailboxer gem. When I place both in the migration that creates the notification and then run a migration it goes through. I then input them into the form and when I submit them there are no errors and the log shows that its take them. For some reason when I try to display them they don't show up, the only thing that is showing is the original things that were part of the migration which is subject and body. My question is how can I add columns to this migration?
Here is the migration with my two columns of lat and long added to the notifications section.
# This migration comes from mailboxer_engine (originally 20110511145103)
class CreateMailboxer < ActiveRecord::Migration
def self.up
#Tables
#Conversations
create_table :conversations do |t|
t.column :subject, :string, :default => ""
t.column :created_at, :datetime, :null => false
t.column :updated_at, :datetime, :null => false
end
#Receipts
create_table :receipts do |t|
t.references :receiver, :polymorphic => true
t.column :notification_id, :integer, :null => false
t.column :read, :boolean, :default => false
t.column :trashed, :boolean, :default => false
t.column :deleted, :boolean, :default => false
t.column :mailbox_type, :string, :limit => 25
t.column :created_at, :datetime, :null => false
t.column :updated_at, :datetime, :null => false
end
#Notifications and Messages
create_table :notifications do |t|
t.column :type, :string
t.column :body, :text
t.column :subject, :string, :default => ""
t.column :lat, :text
t.column :long, :text
t.references :sender, :polymorphic => true
t.references :object, :polymorphic => true
t.column :conversation_id, :integer
t.column :draft, :boolean, :default => false
t.column :updated_at, :datetime, :null => false
t.column :created_at, :datetime, :null => false
end
#Indexes
#Conversations
#Receipts
add_index "receipts","notification_id"
#Messages
add_index "notifications","conversation_id"
#Foreign keys
#Conversations
#Receipts
add_foreign_key "receipts", "notifications", :name => "receipts_on_notification_id"
#Messages
add_foreign_key "notifications", "conversations", :name => "notifications_on_conversation_id"
end
def self.down
#Tables
remove_foreign_key "receipts", :name => "receipts_on_notification_id"
remove_foreign_key "notifications", :name => "notifications_on_conversation_id"
#Indexes
drop_table :receipts
drop_table :conversations
drop_table :notifications
end
end
My show view looks like
%h1= conversation.subject
%ul
= content_tag_for(:li, conversation.receipts_for(current_user)) do |receipt|
- message = receipt.message
%h3= message.subject
%p= message.body
%p= message.lat
%p= message.long
= render 'messages/form', conversation: conversation
This is what comes up in the console, for lat and long you see it says null
Notification Load (0.1ms) SELECT "notifications".* FROM "notifications" ORDER BY "notifications"."id" DESC LIMIT 1
--- !ruby/object:Message
attributes:
id: 4
type: Message
body: game
subject: wiz
lat: !!null
long: !!null
sender_id: 1
sender_type: User
conversation_id: 2
draft: false
updated_at: 2013-03-10 04:37:54.984277000Z
created_at: 2013-03-10 04:37:54.984277000Z
notified_object_id: !!null
notified_object_type: !!null
notification_code: !!null
attachment: !!null
=> nil
I am not sure I understand exactly what you are doing, but it sounds like possibly you haven't added the two new columns to attr_accessible and they aren't being saved because of that. That's the first thing I would check (it's in the model).
Otherwise, go to the console and see if your new columns are there and see if there is data in them. That will help you find where the problem is.

rake db:migrate error wrong number of arguments (5 for 4)

This is my migration file:
class AddSeoMetaInfoToArticles < ActiveRecord::Migration
def self.up
add_column :articles, :seo_title, :string, { :default => "", :null => false }
add_column :articles, :seo_description, :string, { :default => "", :null => false }
add_column :articles, :seo_keywords, :string, :string, { :default => "", :null => false }
end
def self.down
remove_column :articles, :seo_keywords
remove_column :articles, :seo_description
remove_column :articles, :seo_title
end
end
When I try to run 'rake db:migrate' I get the following error
$ rake db:migrate
AddSeoMetaInfoToArticles: migrating =======================================
-- add_column(:articles, :seo_title, :string, {:default=>"", :null=>false})
-> 0.0341s
-- add_column(:articles, :seo_description, :string, {:default=>"", :null=>false})
-> 0.0100s
-- add_column(:articles, :seo_keywords, :string, :string, {:default=>"", :null=>false})
rake aborted!
An error has occurred, this and all later migrations canceled:
wrong number of arguments (5 for 4)
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
I'm relatively new to rails and I'm not sure what I'm doing wrong. This is Rails 3.0.9, and a Postgres db if that makes a difference.
add_column :articles, :seo_keywords, :string, :string, { :default => "", :null => false }
has :string twice, so you end up with 5 arguments being passed instead of 4.
You might also want to consider writing you migration with change - your migration is equivalent to
class AddSeoMetaInfoToArticles < ActiveRecord::Migration
def change
change_table :articles do |t|
t.string :seo_title, :default => "", :null => false
t.string :seo_description, :default => "", :null => false
t.string :seo_keywords, :default => "", :null => false
end
end
end
which I find easier on the eye. It also has the advantage that you can pass :bulk => true to change_table which will combine all 3 column additions into 1 alter table statement, which is usually much faster.
Both ways will of course work.
You give the :string argument twice in this line:
add_column :articles, :seo_keywords, :string, :string, { :default => "", :null => false }

Rails 3 migration

Current migration:
t.string "email", :default => "", :null => false
add_index :users, :email, :unique => true
I want to create a new migration to remove the :null => false requirement and also remove the default => "" for email. Also, I would like to change the index to remove :unique => true. What's the syntax?
I haven't done much with indices, and there doesn't seem to be a change_index method on ActiveRecord::Migration, but you can try something like this:
class ChangeUserStuff < ActiveRecord::Migration
def self.up
change_column :users, :email, :default => "", :null => true
remove_index :users, :column => :email
add_index :users, :email
end
def self.down
change_column :users, :email, :default => "", :null => false
remove_index :users, :column => :email
add_index :users, :email, :unique => true
end
end
There was some funny behavior regarding changing :null options, but I believe setting them to true instead of omitting should handle it.

Resources