I created a model in my Rails app and realized after some time that I had forgotten to add some attributes, and later added them via a generated migration.
I now realize that the order of the attribute columns in schema.rb is the order that they will appear in a generated resource view in ActiveAdmin.
I want to reorder the columns when I view that model in ActiveAdmin, and the only way I have thought to do so is by changing the column order in the database.
I have looked here and here, and attempted to run a database migration using change_table or change_column. This had no resulting change.
This is migration I ran, which had no result:
class Reordercolumn < ActiveRecord::Migration[5.0]
def up
change_table :student_details do |t|
t.change :exact_length, :text, after: :length_of_stay
t.change :returned_home, :boolean, after: :spouse_name
t.change :has_spouse, :boolean, after: :expectation
end
end
end
Looking to view attribute columns in ActiveAdmin in a particular order, I ran a database migration to change columns, but the migration is not reordering the columns.
You need to reorder columns in ActiveAdmin? Let's do it in corresponding admin/student_detail.rb file
index do
selectable_column
column :exact_length
column :returned_home
column :has_spouse
end
show do
attributes_table do
row :title
row :returned_home
row :has_spouse
end
end
More info about customizing index and show views you can find in the docs
Related
I’ve started learning Ruby on Rails recently. I did a blogger tutorial. I want to add one more field archive to my database, but not sure is it possible just to write manually and which command to call?
Here is my database where I want to add code:
class CreateArticles < ActiveRecord::Migration[6.1]
def change
create_table :articles do |t|
t.string :title
t.text :body
t.timestamps
end
end
end
And I want to add a new field archive which is boolean and by default false?
Also is it okay to add in this schema new field or is it better in some other?
1.Run the migration from command line to add the new column
$ rails g migration add_column_archive_to_articles archive:boolean
The above command will create a new migration file in your db/migrate folder.
2.As of now there's no option to add default value to a column, which can be defined through terminal. Set the new column value to true/false by editing the new migration file created. Your migration file will look like this.
class AddColumnArchiveToArticles < ActiveRecord::Migration
def change
add_column :articles, :archive, :boolean, default: false
end
end
3.Then do
$ rails db:migrate
Migrations should never be changed afterwords. That is why they are migrations, and not a static schema definitions.
Just generate a new migration using rails g migration AddArchiveToArticles and then check the rails documentation for add_column to see how you can alter a table to add a column. It also supports default values :)
Let's say I want to add a column on my users table running the following migration
class AddVersionHistoryToUsers < ActiveRecord::Migration
def change
add_column :users, :versions, :string, array: true, default: '{}'
User.find_each do |user|
if user.app_version?
user.versions << user.app_version.to_s
user.save!
end
end
end
end
My aim is to insert the current app_version of each user into the versions array. How can I execute a migration without a lock in the users table due to the default value?
To wrap this up: Looping and querying the database for every User is highly inefficient. You should use update_all for these tasks.
And since your data already exists in the same table you can simply get it from there.
User.where.not(app_version: nil).update_all('versions = ARRAY[app_version]')
My question is really simple. I created this migration file and my mobile column didn't change BUT def change was created. Is it because rails ignored def up and def down? if so why?
def change
add_column :posts, :address, :string
end
def up
execute 'ALTER TABLE posts ALTER COLUMN mobile TYPE integer USING (mobile::integer)'
end
def down
execute 'ALTER TABLE posts ALTER COLUMN mobile TYPE text USING (mobile::text)'
end
Rails will not run both the change and up methods by design thus ignoring everything after the change method. When you need to run some specific logic like in your Up and Down methods you have two choices. You can either put the stuff in your change method into the up and down methods or you can put the Up and Down stuff into the change method. If you want to do this the "Rails4" way you should use change and the reversible method to get what you need:
class SomeMigration < ActiveRecord::Migration
def change
add_column :posts, :address, :string
reversible do |change|
change.up do
execute 'ALTER TABLE posts ALTER COLUMN mobile TYPE integer USING (mobile::integer)'
end
change.down do
execute 'ALTER TABLE posts ALTER COLUMN mobile TYPE text USING (mobile::text)'
end
end
end
I want to drop a table that has changed a few times (add columns, rename, add index..10 migration files)
If I do:
def up
drop_table :tablename
end
def down
create_table :tablename do |t|
t.string :string
...
end
end
On the down method, do I have to include all the columns as they were in the last state of the table? Or will rails be smart enough to remember its last state?
Thanks!
rails is smart, but its not the job of rails to remember the state of the tables that were dropped. So you have to make sure that you create the table with the columns that you would expect at this state.
I want a migration to create a clone of an existing table by just suffixing the name, including all the indexes from the original table.
So there's a "snapshots" table and I want to create "snapshots_temp" as an exact copy of the table (not the data, just the table schema, but including the indexes).
I could just copy and paste the block out of the schema.rb file and manually rename it.
But I'm not sure by the time this migration is applied if the definition from schema.rb will still be accurate. Another developer might have changed the table and I don't want to have to update my migration script.
So how might I get the schema of the table at runtime? Essentially, how does 'rake schema:dump' reverse engineer the table so I can do the same in my migration? (but changing the table name).
Try doing it with pure SQL. This will do what you want:
CREATE TABLE new_tbl LIKE orig_tbl;
In Rails 4 & PostgreSQL, create a new migration and insert:
ActiveRecord::Base.connection.execute("CREATE TABLE clone_table_name AS SELECT * FROM source_table_name;")
This will create the clone with the exact structure of the original table, and populate the new table with old values.
More info: http://www.postgresql.org/docs/9.0/static/sql-createtableas.html
This will do. It's not perfect, because it won't copy table options or indices. If you do have any table options set, you will have to add them to this migration manually.
To copy indices you'll have to formulate a SQL query to select them, and then process them into new add_index directives. That's a little beyond my knowledge. But this works for copying the structure.
class CopyTableSchema < ActiveRecord::Migration
def self.up
create_table :new_models do |t|
Model.columns.each do |column|
next if column.name == "id" # already created by create_table
t.send(column.type.to_sym, column.name.to_sym, :null => column.null,
:limit => column.limit, :default => column.default, :scale => column.scale,
:precision => column.precision)
end
end
# copy data
Model.all.each do |m|
NewModel.create m.attributes
end
end
def self.down
drop_table :new_models
end
end
Copy the tables entry from your projects db/schema.rb straight into your migration. Just change the table name and your good to go.
It looks like this logic is wrapped up in ActiveRecord::SchemaDumper but it only exposes an all-in-one "dump" method and you can't dump just a specific table (the "table" method is private).