For rails, is creating the 'ar_internal_metadata' table with a handwritten migration a good idea? - ruby

When I run a migration, the 'ar_internal_metadata' table keeps being stripped out of the schema.
create_table 'ar_internal_metadata', primary_key: 'key', force: :cascade do |t|
t.datetime 'created_at', null: false
t.datetime 'updated_at', null: false
t.string 'value'
end
If I were to create the 'ar_internal_metadata' with a manual migration, would it work fine or cause problems?

keeps being stripped out of the schema.
This is expected behaviour:
# activerecord/lib/active_record/schema_dumper.rb
def ignored?(table_name)
[ActiveRecord::Base.schema_migrations_table_name, ActiveRecord::Base.internal_metadata_table_name, ignore_tables].flatten.any? do |ignored|
ignored === remove_prefix_and_suffix(table_name)
end
end

Related

Creating an ActiveRecord database for a webcrawler. Having issues adding index

I'm working on a three part program for a webcrawler program for school. My first step is to just create the database using activerecord and knowing that it will be queried later using sqlite3. The database actually does get created with my current program. However, it errors out when gets to "add_index". I'm not great with databases in general so guidance is appreciated.
Before I put in my code the error is:
crawler_create.rb:23: syntax error, unexpected ',', expecting ')'
add_index (:pages,[:url], unique=> true)
Here's what I've come up with so far:
require 'active_record'
require 'sqlite3'
db=SQLite3::Database.new("crawler.db")
ActiveRecord::Base.establish_connection(adapter:'sqlite3',database:'crawler.db')
ActiveRecord::Schema.define do
create_table :pages do |t|
t.string :url, :null => false
t.string :title
t.string :content_type
t.date :last_modified
t.string :status
end
end
add_index (:pages,[:url], unique=> true)
ActiveRecord::Schema.define do
create_table :links do |t|
t.integer :from_page_id, :null => false
t.integer :to_page_id, :null => false
end
end
add_index(:links,[:from_page_id,:pages_id], :unique =>true)
ActiveRecord::Schema.define do
add_foreign_key :from_page_id, :pages_id
add_foreign_key :to_page_id,:pages_id
end
It looks like you got a simple syntax error here:
add_index (:pages, [:url], unique: true)
I'd suggest that you use a consistent hash syntax, either using hash rockets => or the newer syntax unique: true.

Add column to schema before created_at column

I'm trying to add a column to my table.
Here is my migration file:
class AddEmail < ActiveRecord::Migration
def change
add_column :apps, :email, :string, after: :website
end
end
However, when I run it, the newly created email column goes all the way to the last column after updated_at:
ActiveRecord::Schema.define(version: 20141217210326) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "apps", force: true do |t|
t.string "name"
t.string "iTunes"
t.string "website"
t.datetime "created_at"
t.datetime "updated_at"
t.string "email"
end
end
What I want is for the new email column to go in between the website and created_at column. How do I do that?
Postgres doesn't support the ordering of columns in tables. If you don't have any code in production, just alter the original migration that creates the apps table.

Rails if #model.save is throwing an error

I have a Message model. Whenever I run if #message.save in my controller I get this error:
ERROR: null value in column "conversation_id" violates not-null constraint
I just want to redirect if save fails.
def create
#message = Message.new(message_params)
if #message.save
# redirect
else
# render new
end
end
My schema for messages
create_table "messages", force: true do |t|
t.string "body", null: false
t.integer "conversation_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
I believe the reason this is happening is because there is no validation in your actual model, only in the db. Therefore, it is passing the validation to continue saving, but the db has a problem with it. Simply include a validation in your model, and it will return false:
validates :conversation_id, presence: true

SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer/

I ran the command
rails g migration AddUser_idToComments User_id:string
and then I figured out that User_id should be an integer and so I ran
rails g migration AddUser_idToComments User_id:integer --force thinking that it would overwrite the initial command.
But now, I'm getting this error:
```
louismorin$ rake db:migrate
== 20140910155248 AddIndexToComments: migrating ===============================
-- add_column(:comments, :Index, :string)
-> 0.0069s
== 20140910155248 AddIndexToComments: migrated (0.0070s) ======================
== 20140910181022 AddUserIdToComments: migrating ==============================
-- add_column(:comments, :User_id, :integer)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in change'
ActiveRecord::StatementInvalid: SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:inchange'
SQLite3::SQLException: duplicate column name: User_id
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
```
Here's my schema.rb file
```
ActiveRecord::Schema.define(version: 20140910155210) do
create_table "comments", force: true do |t|
t.text "body"
t.integer "post_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "User_Id"
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
create_table "posts", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "topic_id"
end
add_index "posts", ["topic_id"], name: "index_posts_on_topic_id"
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
create_table "topics", force: true do |t|
t.string "name"
t.boolean "public", default: true
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "role"
t.string "avatar"
t.string "Image"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
```
Because of the error, your second migration -- changing the column type -- didn't run. If that migration was only intended to change that one column, we could then delete the file it generated and try again.
If you don't yet have any data in that column that you care about, that's pretty easy:
rails g migration ChangeTypeOfUserIdOnComments
This migration name isn't special. Might as well have been DoWhateverIWant
Then, edit the created migration's change method to something like this:
def change
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
end
When you then run your un-run migrations rake db:migrate, it shouldn't trip up on the one which errored (because we deleted it), and then it should run this one, which removes the column and adds it back with the correct type.
If you DO have data you want to save, the procedure is more complicated. Your change method would have to grab the current user_id's for each comment, and then assign them to the new comments when we create the new column. The below should hopefully work:
def change
user_ids = {}
Comment.find_each{ |c| user_ids[c.id] = c.user_id.to_i }
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
Comment.each{ |c| c.update_attribute(:user_id, user_ids[c.id])
end
Also note that the names of the migration in the command are generally all CamelCase or all snake_case. So: AddColumnUserIdToComments or add_column_user_id_to_comments. Naming as you did might cause problems.
** EDIT **
Modify a Column's Type in sqlite3
It appears that SQLite has NO good way to modify/drop a column. I'd suggest either:
Dropping and restarting a SQLITe table
Drop the table, drop the original user_id migration and the line in the new one about removing the old user_id column, and then create a new table with the new migrations. Should work fine if you don't care about your data
Switching to Postgres, which is the database Heroku uses.
It's probably a good idea (because you want your production and local databases to behave identically), but can be bug-prone to switch to.
Look here for guidance -- Change from SQLite to PostgreSQL in a fresh Rails project

Devise login validation failure

I rails3.0.4 and devise installed with following users table
create_table "users", :force => true do |t|
t.string "login"
t.string "email"
t.string "crypted_password", :null => false
t.string "password_salt", :null => false
t.string "persistence_token", :null => false
t.string "single_access_token", :null => false
t.string "perishable_token", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "database_authenticatable", :null => false
t.string "recoverable"
t.string "rememberable"
t.string "trackable"
t.string "reset_password_token"
end
The users table was not created by devise but I added the necessary
columns in migration.
And following settings in config/initializers/devise.rb
config.authentication_keys = [ :email]
But every time I try to sign up as a new user it throws:
2 errors prohibited this user from being saved:
Login is too short (minimum is 3 characters)
Login should use only letters, numbers, spaces, and .-_# please.
Any ideas why it could happen?
Yes, the login is too short and/or contains the wrong characters :)
You enabled the devise built-in validations, and that's what they validate. To use your own validations remove :validatable from your devise inclusion in app/models/user.rb
If you're interested, the validation used by devise is defined in lib/devise/models/validatable.rb in the devise gem.
Should the validation not be the problem you'll have to show the log of a user creation request, so that we can see what parameters are submitted.
EDIT: Oh I see, I misread - it's about "login". Well, see comments below.

Resources