Weird Rails migration behaviour - repeating add_references commands and failing with ActiveRecord::StatementInvalid: PG::DuplicateColumn - ruby-on-rails-5

I'm running Rails 5.2.4.4 and have found the strangest behaviour when I have two add_references listed in my users migration. Even though they are unique lines for different table references, the output shows the first one repeated, then failing due to duplicate column. If I switch the statements around, it simply causes the other add_reference to repeat and fail:
Migration:
def change
add_column :users, :first_name, :string
add_column :users, :last_name, :string
add_column :users, :authentication_token, :string
add_column :users, :location, :string
add_column :users, :is_admin, :boolean, default: false
add_column :users, :account_active, :boolean, default: true
end
add_reference :users, :tagging, type: :uuid, foreign_key: true, null: true
add_reference :users, :tenant, type: :uuid, foreign_key: true
add_index :users, :created_at
Results in this error:
-- add_reference(:users, :tagging, {:type=>:uuid, :foreign_key=>true, :null=>true})
-- add_reference(:users, :tagging, {:type=>:uuid, :foreign_key=>true, :null=>true})
rails aborted!
ActiveRecord::StatementInvalid: PG::DuplicateColumn: ERROR: column "tagging_id" of relation "users" already exists
If I switch the add_references columns around:
add_reference :users, :tenant, type: :uuid, foreign_key: true
add_reference :users, :tagging, type: :uuid, foreign_key: true, null: true
I instead get:
-- add_reference(:users, :tenant, {:type=>:uuid, :foreign_key=>true})
-- add_reference(:users, :tenant, {:type=>:uuid, :foreign_key=>true})
rails aborted!
ActiveRecord::StatementInvalid: PG::DuplicateColumn: ERROR: column "tenant_id" of relation "users" already exists
Thanks in advance.

Found the issue...
I had placed the add_references code outside the def change block.
Shifted it and all fixed.

Related

How to check emptiness on devise custom fields?

I've added two news fields to my users table :first_name and :last_name
In migration file I've specified these fields couldn't be null using the following code:
class Userscustomfields < ActiveRecord::Migration
def change
add_column :users, :first_name, :string, {:null => false, :limit => "128"}
add_column :users, :last_name, :string, {:null => false, :limit => "128"}
end
end
I've checked on my database and the table was configurated correctly. But when I'm going to do a new register, my rails app allows to me to add a new user with first and last names empty. The app saves the fields with "", which didn't worked as I expected.
How can I do prevent this, by making a check of emptiness on my field before save them on my database?
I put on model user.rb
validates :first_name, :last_name, presence: true

Rails 3.2 + Rolify: Application breaks after installing Rolify (Bug?)

I have this Rails 3.2 application running fine. I installed Rolify by following the steps below:
Add gem "rolify" to the Gemfile
Run bundle install
Run rails g rolify:role
Check the new migrations, the new files and the modified files (generated/modified by the command above).
Run rake db:migrate
At this point, I try to create/edit a User and I get the following error:
NoMethodError in UsersController#create
undefined method `user_id' for #<User:0x007f8f21f168e8>
Note that before I installed Rolify, everything was working fine, so the problem comes from Rolify.
Here are the migration, the new file and the modified file in question:
The new migration:
class RolifyCreateRoles < ActiveRecord::Migration
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, :polymorphic => true
t.timestamps
end
create_table(:users_roles, :id => false) do |t|
t.references :user
t.references :role
end
add_index(:roles, :name)
add_index(:roles, [ :name, :resource_type, :resource_id ])
add_index(:users_roles, [ :user_id, :role_id ])
end
end
The new model:
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
end
The modified model:
class User < ActiveRecord::Base
rolify
has_secure_password
has_many :issues
acts_as_tenant(:client)
attr_accessible :email, :password, :password_confirmation, :username
validates :username, presence: true,
length: { within: 4..50 },
format: { with: /(?:[\w\d]){4,255}/ }
validates_uniqueness_to_tenant :username, case_sensitive: false
validates :email, presence: true,
uniqueness: { case_sensitive: false },
length: { within: 8..255 },
format: { with: /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i }
validates :password, presence: true, on: :create,
confirmation: true,
length: { within: 4..255 }
validates :password_confirmation, presence: true, on: :create
# NOTE: Used by SimpleForm to display the dropdown proerply
def to_label
"#{username}"
end
end
You can find the rest of the files in the project in the Github repo
Does anyone have a clue where the error comes from please?
This error is happening because the acts_as_tenant is (mistakenly) creating a validation for a user_id field on your User model. You can see this validator if you run this code inside rails c:
User._validators
I would recommend to switch to the apartment gem which appears to be more maintained than acts_as_tenant.

has_many & belongs_to migration with foreign keys and database constraints in postgres?

I've searched several questions about migrations and their answers, but I didn't find a satisfactory solution.
I want to use simple has_many and belongs_to relationships like
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
Is there any possibility to create database level constraints inside of the migration such as
post_id integer REFERENCES posts
or will I have to do this manually? At best I'd prefer a database-independent solution. Thanks in advance!
Edit: I'm currently using Postgresql, but I like to be flexible in regards of the underlying database.
Update: For the sake of database-independent code I stick with the following migration at the moment:
class AddRelations < ActiveRecord::Migration
def self.up
add_column :posts, :user_id, :integer, :null => false
add_column :comments, :user_id, :integer, :null => false
add_column :comments, :post_id, :integer, :null => false
end
def self.down
remove_column :posts, :user_id
remove_column :comments, :user_id
remove_column :comments, :post_id
end
end
I still hope to find a more elegant solution. Maybe there's a gem for that.
Use the excellent foreigner gem to add the foreign keys in your migration:
add_foreign_key :posts, :users
add_foreign_key :comments, :users
add_foreign_key :comments :posts

Heroku - Migration failing, how to change migration to run on Heroku?

I've got a migration file which does the following:
class ChangeLoginToUsername < ActiveRecord::Migration
def self.up
remove_column :users, :login, :string
add_column :users, :username, :string
end
def self.down
remove_column :users, :username, :string
add_column :users, :login, :string
end
end
This ran in fine on my local dev but I've now noticed the third parameter for the filed type on remove_column is erroring when I try and run this migration on Heroku. Is there a way to write/run specific migrations just for Heroku? There are 2 further migrations after this one that I need to run...
Any help hugely appreciated as always
It doesn't make sense for remove_column to have a data type:
class ChangeLoginToUsername < ActiveRecord::Migration
def self.up
remove_column :users, :login
....
end
def self.down
remove_column :users, :username
...
end
end

Authlogic issue only in migration in rails 3 project

I'm trying to run the following migration
def self.up
add_column :users, :perishable_token, :string
User.all.each { |u| u.reset_perishable_token! }
change_column :users, :perishable_token, :string, :null => false
add_index :users, :perishable_token
end
and the u.reset_perishable_token! code behaves strangely (no return value, doesn't change the database field). Consequently change_column ..., :null => false fails with
users.perishable_token may not be NULL
Even separating the migration into two doesn't do the trick either if I run them with just one rake command.
Part One
def self.up
add_column :users, :perishable_token, :string
add_index :users, :perishable_token
end
Part Two
def self.up
User.all.each { |u| u.reset_perishable_token! }
change_column :users, :perishable_token, :string, :null => false
end
Only if I run the first and second migration in separate rake processes everything runs fine.
What could possibly be the reason and how can I fix it?
I think you need to add...
User.reset_column_information
...after you have added the perishable_token to the users_table, otherwise the User model is out of sync with the database.
I think the User model would only be loaded once per 'rake db:migrate', so it wouldn't help to split the migration in two.