Ruby on Rails mysql migrate use Timezone instead of Datetime - mysql

I am keeping in my mysql table a column called
starts_at
my column can be with a different timezone each time.
I have tried creating a migration:
def self.up
create_table :meetings, id: false, force: true do |t|
t.string :id
t.timestamp :starts_at
end
end
but i always end up with a
datetime
column type
i want to force rails to use timestamp, and tried all of these with with no success:
def up
change_column :meetings, :starts_at, :timestamp
end
this:
def up
change_column :meetings, :starts_at, 'timestamp'
end
and this:
def self.up
create_table :meetings, id: false, force: true do |t|
t.string :id
t.column :starts_at, 'timestamp'
end
end
any ideas?
update:
i want to save the timezone on the database record and not on the
application configuration

Rails actually makes some of decisions for you. Both :timestamp and :datetime will default to DATETIME, while :date and :time corresponds to DATE and TIME, respectively.
Using Rails, you only have to decide whether you need to store date, time or both.
So you can use type :datetime in your :starts_at column.

Look at this example in config/application.rb
class Application < Rails::Application
config.time_zone = 'Sydney'
config.time_zone = 'Kuala Lumpur'
config.active_record.default_timezone = 'Kuala Lumpur'
end
You can set your Time zone according to requirement and you can make it dynamic.
Here is all timezone ActiveSupport::TimeZone.all.map(&:name)

Related

Migration - How to add a UNIQUE constraint to an already populated table?

I have a technicians table which consists only of name and timestamps columns in production, but now I need to use it as a devise model.
class Technician < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
end
Using 'rails generate devise technician' led me to a migration with all that is necessary to make my technician model a devise model.
class AddDeviseToTechnicians < ActiveRecord::Migration
def change
change_table(:technicians) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
end
end
end
But I can't migrate since email is a 'unique: true' column, nor drop my technicians table. What should I do?
I was thinking of setting the email field of each technician as: name_attribute + "#email.com", but what's the best way to do this?
I'm using a MYSQL database.

Rails with mysql cannot create json type column

I have created Rails(3.2) application with mysql(5.7.16) backend. I can't add json type column when creating table but I can able to add json column by new migration. I have used following code in create table migration, What was wrong here ?
class CreateShoppingCartItemSpecialInfos < ActiveRecord::Migration
def change
create_table :shopping_cart_item_special_infos do |t|
t.integer :shopping_cart_checkout_option_id
t.json :special_info
t.timestamps
end
end
end
You should be able to create JSON column type. Probably you run in couple of errors. In case there is a error after migration try first reverting it:
rake db:migrate:down VERSION=<version>
Than you can try like this:
class CreateShoppingCartItemSpecialInfos < ActiveRecord::Migration
def change
create_table :shopping_cart_item_special_infos do |t|
t.integer :shopping_cart_checkout_option_id
t.column :special_info, :json
t.timestamps
end
end
end

Rails 5—How to add UUID column

There doesn't seem to be much documentation on UUIDs in Rails 5. All I've found is this code:
create_table :users, id: :uuid do |t|
t.string :name
end
That works great if you're creating a table, but what if you're updating an already-existing table?
How do you add a UUID column to a table?
To migrate from default id to use uuid, try writing migration like this:
class ChangeProjectsPrimaryKey < ActiveRecord::Migration
def change
add_column :projects, :uuid, :uuid, default: "uuid_generate_v4()", null: false
change_table :projects do |t|
t.remove :id
t.rename :uuid, :id
end
execute "ALTER TABLE projects ADD PRIMARY KEY (id);"
end
end
Here's how to add a uuid column to an existing Rails table.
class AddUuidToContacts < ActiveRecord::Migration[5.1]
def change
enable_extension 'uuid-ossp' # => http://theworkaround.com/2015/06/12/using-uuids-in-rails.html#postgresql
add_column :contacts, :uuid, :uuid, default: "uuid_generate_v4()", null: false
execute "ALTER TABLE contacts ADD PRIMARY KEY (uuid);"
end
end
If you forget to add enable_extension 'uuid-ossp', you'll get these errors:
PG::UndefinedFunction: ERROR: function uuid_generate_v4() does not
exist ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR:
function uuid_generate_v4() does not exist

Rails rollback, change type and migrate again

I have a requests table;
class CreateRequests < ActiveRecord::Migration
def change
create_table :requests do |t|
t.string :from
t.string :to
t.timestamps null: false
end
end
end
I would like to rollback the database with rake db:rollback STEP = 5
destroy the Request model and create request table with;
t.datetime :from
t.datetime :to
However, I have a migration table to Request model on STEP = 2,
class AddStatusToRequest < ActiveRecord::Migration
def change
add_column :requests, :status, :string, :default => "Pending"
end
end
The problem is, if I destroy Request table and create new Request table with datetime types it creates after STEP = 2 and when I rake db:migrate rails does not add Status column to Request table. How can I overcome this?
You can create a new migration to change the column type using change_column:
command line: rails g migration change_request_to_from_column_types'
new migration:
class ChangeRequestToFromColumnTypes < ActiveRecord::Migration
def change
change_column :requests, :from, :datetime
change_column :requests, :to, :datetime
end
end
It's best not to retroactively change migrations after they've been applied to avoid state conflicts like the one you have. Perhaps the simplest solution is to create a new migration to add the types to the requests table using a guard to do nothing if the column already exists:
class AddStatusToRequestIfNotExists < ActiveRecord::Migration
def change
unless column_exists? :requests, :status
add_column :requests, :status, :string, :default => "Pending"
end
end
end
EDIT
You'll also want to make sure that you can run migrations from scratch, so you might want to update your existing migration to guard against a missing table as follows:
class AddStatusToRequest < ActiveRecord::Migration
def change
unless table_exists? :requests
add_column :requests, :status, :string, :default => "Pending"
end
end
end
Not ideal, but it's probably the safest approach.

Rails active record object save action fails because of a malformed query

I have a problem in Rails in the part of my app that handles landing pages for registration emails. When a user is invited to the app, an Invitation active record instance is created, and user is sent an email with a link containing the id of the invitation (a random string token).
Then, when the link is clicked, I store that token in session, and at one point in the service layer, I update it's 'status' attribute to 'clicked', something like this:
#invitation = Invitation.find_by_id(session[:registration][:invitation_token])
unless #invitation.blank?
session[:registration][:account_details]['referer'] = #invitation.promoter.username
unless #invitation.status == APP_CONFIG['invitation_status']['clicked']
#invitation.status = APP_CONFIG['invitation_status']['clicked']
#invitation.save
end
end
Upon executing the #invitation.save line, I get an active record error:
!! #<ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'invitations.' in 'where clause': UPDATE `invitations` SET `status` = 'clicked', `updated_at` = '2015-11-11 11:07:24' WHERE `invitations`.`` = 'fd05ee5a-e790-48cc-9e7e-d30d3e88919b'>
The Invitation's id column name seems to be ommited from the query for some reason, and I can't figure out why. Not sure what is wrong or what to do.
Invitation migration:
class CreateInvitations < ActiveRecord::Migration
def change
create_table :invitations, id: false do |t|
t.string :id, limit: 36, :auto_increment => false
t.string :promoter_id
t.string :email
t.string :status
t.timestamps
end
end
end
Invitation model:
class Invitation < ActiveRecord::Base
#region Callbacks
before_create :set_uid
#endregion
belongs_to :promoter, class_name: 'User', foreign_key: 'promoter_id'
private
def set_uid
self.id = SecureRandom.uuid unless self.id
end
end
You should mark the id column as the primary_key:
create_table :invitations, id: false do |t|
t.string :id, limit: 36, primary_key: true, auto_increment: false
...
I think that in your case the best way to solve this problem is to drop the table and create it again with correct migration. But if there is data that you don't want to loose, you can also try to do it like this:
class MarkIdAsPrimaryKey < ActiveRecord::Migration
def change
change_column :invitations, :id, :string, limit: 36, primary_key: true, auto_increment: false
end
end
Keep in mind that this migration is not reversible, it remains under your responsibility if you will use it ) Good luck !