limit: 1 difference in schema.rb boolean fields - mysql

I recently started noticing that following a deployment to production, I see this git diff in my db/schema.rb there:
- t.boolean "published", limit: 1
+ t.boolean "published"
and
- t.boolean "visible", limit: 1, default: false
+ t.boolean "visible", default: false
Given that the Rails version is the same on both environments, is this just caused by the difference between MySQL versions, respectively 5.5.43 on production and 5.6.23 on development?

Has your Rails version changed? There was a recent change in Rails that could account for this: https://github.com/rails/rails/pull/19066
Basically, since MySQL doesn't have a boolean column type, Rails uses a TINYINT(1) column type for :boolean attributes, which was reflected when the schema was dumped to schema.rb. So far, so good. But then if one tried to load the same schema.rb into PostgreSQL it would fail because Postgres does have a BOOLEAN column type, but declaring a length for BOOLEAN columns is illegal. This bug was fixed by removing the limit: 1 option when dumping :boolean attributes from a MySQL database (it wasn't necessary anyway).
So if the last time your schema was dumped (which happens when you run migrations) you were on Rails 4.2.2 or earlier you would have gotten limit: 1 in schema.rb, and if you subsequently upgraded to 4.2.3 and dumped your schema again the limit: 1 would be gone.
This change doesn't have any effect except for fixing the aforementioned bug—your schema.rb will function exactly the same way it did before—so there's nothing to be concerned about.

Related

When I run db:migrate it changes my :point database types to :integer in the schema.rb. Why?

In my Ruby on Rails app whenever I run "rails db:migrate" it changes existing "point" type fields to "integer" even though it's not part of any migration I defined. My db is a mySQL db. What could be causing this?
Perhaps because point method does not exist in ActiveRecord.
AR natively supports :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :Boolean.
You could try to use a non-native type using:
t.point :point

Rails app using existing database MySQL

I'm a RoR developer and I'm used to create my own databases using scaffold and such. However I was told to create a rails app to an existing populated database. I Searched and i found this:
1. write config/database.yml to reference your database.
2. Run "rake db:schema:dump" to generate db/schema.rb. Here's the
documentation:
$ rake -T db:schema:dump
...
rake db:schema:dump # Create a db/schema.rb file that can be
portably used against any DB supported by AR
3. Convert schema.rb into db/migrate/001_create_database.rb:
Class CreateMigration < ActiveRecord::Migration
def self.up
# insert schema.rb here
end
def self.down
# drop all the tables if you really need
# to support migration back to version 0
end
end
However I saw some comments saying that they lost their data and some saying that it worked. I can't take chances to lose the data from the database. Can someone please give me some more solid explanation? Or a better solution
I had the same problem but I can't use the solution above.
My database was created before than the ruby on rails app and it didn't have the schema_migrations table created, so when it ran this:
if ActiveRecord::Migrator.current_version > 2
# force the next migration 002_create_database.rb to be skipped
ActiveRecord::SchemaMigration.create(version: '2')
# the version '2' above is the version of the file which is (002 becomes 2)
end
it returned false in the if statement thus, it never skip the create_database migration in my case.
I was looking for some way where I can run the migrations and avoid to create tables again and, at the same time, new coders can run it and create the tables.
After some search I found the table_exists? function, so:
I created the schema migration using the rake db:schema:dump
Then I created my first migration: 001_create_database.rb and pasted the schema from the db/schema.rb file
Finally, I edited the migration adding and if statement before each create table:
if !table_exists?("CarsTable")
create_table "CarsTable" do |t|
t.bigint "Owner", null: false
t.string "Color", limit: 20, null: false
t.string "Make", limit: 40, null: false
t.string "Model", limit: 20, null: false
t.string "Plate", limit: 10, null: false
end
end
I tested this in 2 ways, with a database previously created and populated (for production case and my own case) and without any database (for new coders) and it worked.
Rails check all migration files in db/migrate/ and checks if they all are part of the "schema_migrations" table. Your code above will only work for fresh copy of your code (i.e. if I clone your Rails project), because migrations are run in the order of the filename. Since it is 00001_create_d... then it will be the first to be ran on my end, followed by other migration files you have.
You are right that you will then possibly lose data if you migrate, because the schema code you have will be ran after all of your migration files have already been migrated.
Now since it is only you and other developers working on the project, who cannot simply just do rake db:migrate, and that new cloners of your project will have no problems with your code above, then I could do the following below to force that 001_create_database.rb to be already part of your schema_migrations table, thereby skipping it, but not for new cloners (like myself).
IMPORTANT: backup your database first before doing below code
db/migrate/001_safeguard_create_database.rb
class SafeguardCreateDatabase < ActiveRecord::Migration
def up
# if current migration version already has a created database
if ActiveRecord::Migrator.current_version > 2
# force the next migration 002_create_database.rb to be skipped
ActiveRecord::SchemaMigration.create(version: '2')
# the version '2' above is the version of the file which is (002 becomes 2)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
db/migrate/002_create_database.rb
class CreateDatabase < ActiveRecord::Migration
def up
# your schema.rb here
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
After creating these two files, try rake db:migrate. It should only process 001_safeguard_create_database, and skip 002_create_database because it is assumed that your current DB is already set up with it. The 002_create_database then will only be ran for new project users who do not have a DB yet; and for these users, these first two migration files be be ran first, followed by all of your other migrations.

Getting a binary limit from a migration to the schema in Rails

I have a migration for a model with a binary field meant to store a file that can be bigger than 10Mb:
class CreateNewModel < ActiveRecord::Migration
def change
create_table :new_model do |t|
...
t.binary :data, limit: 16777216
...
end
end
end
With the limit information the migration can create a longblob object in a MySQL or MariaDB database, as seen in How do you get Rails to use the LONGBLOB column in mysql?.
The migration seems to work fine on a MariaDB database: data has longblob type. However loading directly from the schema gives data a blob type instead of longblob, this means the rake db:setup command is no longer usable as the schema doesn't reflect the database I want.
This seems pretty evident when one looks at the db/schema.rb file:
create_table "new_model", force: :cascade do |t|
...
t.binary "data"
...
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
There is no limit info and as such loading the schema can only lead to blobs and not longblobs.
Why doesn't the limit information get written in the schema?
I don't want to change the schema manually as it would mean have to redo the change at each migration (as they regenerate the schema file). What other solutions do I have, is there a way to force the limit field from the migration to the schema?
I've tried using the shorthands described in https://github.com/rails/rails/pull/21688 but it doesn't seem to exist in Rails 4.2.6.

How to make Rails generate 'schema.rb' with bigint support for MySQL?

I am using Rails 3.0.5. I am using MySQL as a database storage. I have a model in which one of the columns needs to be BIGINT. I am using the following in my create migration file:
t.column :my_column_name, :bigint
which works fine.
However, when I run
rake db:migrate
the generated 'schema.rb' file creates the following line for the particular column:
t.integer "my_column_name", :limit => 8
which is not correct.
My question is where am I wrong with that? Is there something that I should do in order to get the correct 'schema.rb' file? Can I change the way 'schema.rb' file is generated?
Please, note that the fact that the 'schema.rb' file is wrong causes problems to my continuous integration server, which runs tests and creates the db from scratch (before running tests) using the 'schema.rb' file.
I now realize that
t.integer "my_column_name", :limit => 8
with my_sql driver is CORRECT in the schema.rb file.
The database that is generated using the 'schema.rb' file creates a
bigint(20)
though this may seem strange.
I have found this by investigating the code of my_sql adapter, the snippet of which I quote here:
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
return super unless type.to_s == 'integer'
case limit
when 1; 'tinyint'
when 2; 'smallint'
when 3; 'mediumint'
when nil, 4, 11; 'int(11)' # compatibility with MySQL default
when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}")
end
end
It is clear, there that :limit => 8 will end up creating a bigint in mysql db.

Rails unit tests fail because of unique constraint on schema_migrations

I'm trying to run rake test:units and I keep getting this:
Mysql::Error: Duplicate entry '2147483647' for key 1: INSERT INTO `ts_schema_migrations` (version) VALUES ('20081008010000')
The "ts_" is there because I have ActiveRecord::Base.table_name_prefix set. I'm confused because there is no value '20081008010000' already in the table, and there is no migration with the value '2147483647' (though the value does appear in the table).
In Rails' schema_statments.rb, there is the following:
def initialize_schema_migrations_table
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
unless tables.detect { |t| t == sm_table }
create_table(sm_table, :id => false) do |schema_migrations_table|
schema_migrations_table.column :version, :string, :null => false
end
...
In my development database, ts_schema_migrations.version is a VARCHAR. In test, though it's an INTEGER. I've dropped the tables and re-run the migrations (and/or a rake db:schema:load RAILS_ENV=test) several times. No changes.
Is something wrong with my MySQL adapter?
It looks as though your test schema is Rails 1.x somehow, whereas development is Rails 2. Perhaps you could set RAILS_ENV to test and run rake db:reset
It looks like you skipped some steps when upgrading from Rails 1.x to 2.0.
Go through and read the upgrade notes:
http://www.slashdotdash.net/2007/12/03/rails-2-upgrade-notes/
And the release notes:
http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done
They will tell you all the steps you need to follow. Particularly regenerating all the scripts and migrating your database to the new system of database migrations by timestamp instead of incrementing migration id.