Rails Migration - ruby-on-rails

My migration is as follows:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :email
t.string :password
t.string :name
t.boolean :male
t.boolean :admin
t.timestamps
end
end
def self.down
drop_table :users
end
end
When I go to script/console and type "User", Rails does not recognize the class.

Did you run script/generate model User ... or script/generate migration CreateUser...?
If you do not generate the model, it won't be available in the console, as Rails doesn't know it exists.
Rails also does not create a modelname_id field, it simply creates an id field which autoincrements.
I hope this helps.

1) The migration will create an auto-incrementing "id" column. (I've never seen a migration create a class_id column unless it was specified).
2) You will need to declare this class in a app/model/user.rb file
class User < ActiveRecord::Base
#class methods go here
end
More importantly I want to recommend the restful_authentication plugin. It's the community standard for user authentication (meaning it's battle tested, regularly updated, and conforms to most use cases).

Related

Renaming model with migration

I have an existing model 'micropost' and I found out that there is better name for the model to suit my application. What would be the better approach to rename 'micropost' model to 'story' model without affecting its indexes? I am working on Rails 5.0.0.rc1. The migration snippet is:
class CreateMicroposts < ActiveRecord::Migration
def change
create_table :microposts do |t|
t.text :content
t.references :user, index: true
t.timestamps null: false
end
add_index :microposts, [:user_id, :created_at]
end
end
1 .Make migration to change the database table name from micropost to story.
class RenameOldTableToNewTable< ActiveRecord::Migration
def change
rename_table :old_table_name, :new_table_name
end
end
2 .Change manually the Active Record model class into Story
Run command on console:
$ rails g migration RenameMicropostToStory
Edit migration file:
class RenameMicropostToStory < ActiveRecord::Migration
def change
rename_table :microposts, :stories
end
end
then,
$ rake db:migrate

Migrate postgresql database to uuid rails 3.1

I am using rails 3.1 and ruby 1.9.3,Now i want to use uuid concept in rails 3
so i did like :-
create_table :posts, :id => false do |t|
t.string :uuid, :limit => 36, :primary => true
end
ActiveRecord::Base.class_eval do
set_primary_key 'uuid'
before_create :generate_uuid
def generate_uuid
self.id = UUIDTools::UUID.random_create.to_s
end
end
This is working for new data,now i want to migrate existing data with relation.for uuid they are using datatype as string,in postgresql the data type used for primary_key and foreign key is integer ,so if i am trying to change foreign key integer to string it is throwing error.
Could you please tell me some example,how to do this.
kingston.s
First of all, to use UUIDs in ActiveRecord you need to enable the uuid-ossp extension. Create a new migration.
class EnableUuidOssp < ActiveRecord::Migration
def change
enable_extension 'uuid-ossp'
end
end
Second, you do do not need to use string type in your migrations, there is a uuid type. When creating a new table:
create_table :posts, id: :uuid do |t|
end
This will automatically generate a UUID in the same way that an incremental Integer ID is normally generated. When you want to add a UUID field to an existing table:
change_table :posts do |t|
t.uuid :uuid, default: 'uuid_generate_v4()'
end
The default: 'uuid_generate_v4()' will ensure that a new UUID is generated for you by Postgres.
Third, to actually migrate existing data I guess you would need to create migrations that 1) add UUID fields to all of the models 2) create new UUID foreign keys 3) associate the models using the UUID foreign keys 4) remove the old foreign keys 5) rename the new foreign keys:
class AddUuidToPosts < ActiveRecord::Migration
def change
change_table :posts do |t|
t.uuid :uuid, default: 'uuid_generate_v4()'
end
end
end
# assuming you have a comments table that belongs to posts
class AddUuidToComments < ActiveRecord::Migration
def change
change_table :comments do |t|
t.uuid :uuid, default: 'uuid_generate_v4()'
end
end
end
class AssociateCommentsWithPostings < ActiveRecord::Migration
def change
# Add a uuid_posting_id field to comments relate comments to postings
# through the posting UUID
change_table :comments do |t|
t.uuid :uuid_posting_id
end
# Loop through all existing postings and update all associated comments
# new foreign key field
Posting.all.each do |posting|
# Not sure about this, but you might need to touch the posting to generate
# a UUID
posting.touch
Comment.where(posting_id: posting.id).
update_all(uuid_posting_id: posting.uuid)
end
remove_column :comments, :posting_id
rename_column :comments, :uuid_posting_id, :posting_id
end
end
# You don't need to override ActiveRecord::Base to set the primary key to :uuid.
# Only do this in existing models that you migrated to UUIDs. In any new tables
# that you create, the id column will be a UUID, as long as you use the migration
# format that I showed you at the top.
class Posting < ActiveRecord::Base
set_primary_key :uuid
end
You should probably go the extra mile and actually remove the old Integer id fields and rename the new UUID ids to "id" but I'm not sure how to do that off the top of my head. Anyway, I think this approach should work. There could be a couple of errors or bits missing though, it's a bit late over here.

Why are the methods up and down not being created with my subclass of ActiveRecord::Migration?

I'm reading Rails 3 in Action and following the commands verbatim. However, when I run the commands
rails new things_i_bought
cd things_i_bought
bundle install
rails generate scaffold purchase name:string cost:float
The book says I should get this code:
class CreatePurchases < ActiveRecord::Migration
def self.up #not created in my code
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
def self.down # not created in my code
drop_table :purchases
end
end
I get this code instead:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
end
Why are the class methods up and down not being created for me? I'm using
rails 3.1.1 and ruby 1.9.2.
thanks for reading my book!
As JacobM and dbalatero have already explained, this is a new feature in Rails 3.1. This particular feature was added by Aaron Patterson as a way to simplify the migration syntax. In earlier versions of Rails, you would have to do as the book shows:
class CreatePurchases < ActiveRecord::Migration
def self.up
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
def self.down
drop_table :purchases
end
end
But that's kind of repeating yourself. Aaron created a migration syntax that looks good and is simpler, calling only the methods necessary for migrating forward, but also allowing the migrations backwards (known as a "rollback") too. The same migration written with the Rails 3.1 syntax is this:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
end
So when this migration runs "forwards", Rails will create the purchases table with the fields. When you roll it back (or run it "backwards") then Rails will know to drop the table.
This syntax isn't entirely perfect however, and you'll run into problems with methods such as change_column. When that happens, it's best to stick with defining both the def up and def down methods in the migrations:
class CreatePurchases < ActiveRecord::Migration
def up
change_column :purchases, :cost, :integer
end
def down
change_column :purchases, :cost, :float
end
end
That's because in this example Rails won't know how to switch it back to the previous type. I hope this explains it better!
This is a new feature in Rails 3.1. For changes that Rails can figure out how to reverse, such as creating a table, you simply create a "change" method with the code that would have gone in "up", and it figures out how to do "down" on it's own.
You can also define "up" and "down" methods yourself -- for some changes (such as dropping a column) Rails won't be able to figure it out -- but the syntax is a bit different; it's not just def up instead of def self.up (they're now instance methods instead of class methods).
I believe in the new Rails 3.1, the database migration methods are self-aware about how to run an up/down migration.
Therefore, if you define a def change method, it will try to use those self-aware methods: in this case, create_table knows to do DROP TABLE in a down context, and CREATE TABLE in an up context.
If you want the old style, you can probably keep using it and define your own self.down and self.up methods as the book describes.
Edit: here's a link to the blog post on this, called "Reversible Migrations": http://www.edgerails.info/articles/what-s-new-in-edge-rails/2011/05/06/reversible-migrations/index.html

Rails has_and_belongs_to_many migration

I have two models restaurant and user that I want to perform a has_and_belongs_to_many relationship.
I have already gone into the model files and added the has_and_belongs_to_many :restaurants and has_and_belongs_to_many :users
I assume at this point I should be able to do something like with Rails 3:
rails generate migration ....
but everything I have tried seems to fail. I'm sure this is something really simple I'm new to rails so I'm still learning.
You need to add a separate join table with only a restaurant_id and user_id (no primary key), in alphabetical order.
First run your migrations, then edit the generated migration file.
Rails 3
rails g migration create_restaurants_users_table
Rails 4:
rails g migration create_restaurants_users
Rails 5
rails g migration CreateJoinTableRestaurantUser restaurants users
From the docs:
There is also a generator which will produce join tables if JoinTable
is part of the name:
Your migration file (note the :id => false; it's what prevents the creation of a primary key):
Rails 3
class CreateRestaurantsUsers < ActiveRecord::Migration
def self.up
create_table :restaurants_users, :id => false do |t|
t.references :restaurant
t.references :user
end
add_index :restaurants_users, [:restaurant_id, :user_id]
add_index :restaurants_users, :user_id
end
def self.down
drop_table :restaurants_users
end
end
Rails 4
class CreateRestaurantsUsers < ActiveRecord::Migration
def change
create_table :restaurants_users, id: false do |t|
t.belongs_to :restaurant
t.belongs_to :user
end
end
end
t.belongs_to will automatically create the necessary indices. def change will auto detect a forward or rollback migration, no need for up/down.
Rails 5
create_join_table :restaurants, :users do |t|
t.index [:restaurant_id, :user_id]
end
Note: There is also an option for a custom table name that can be passed as a parameter to create_join_table called table_name. From the docs
By default, the name of the join table comes from the union of the
first two arguments provided to create_join_table, in alphabetical
order. To customize the name of the table, provide a :table_name
option:
The answers here are quite dated. As of Rails 4.0.2, your migrations make use of create_join_table.
To create the migration, run:
rails g migration CreateJoinTableRestaurantsUsers restaurant user
This will generate the following:
class CreateJoinTableRestaurantsUsers < ActiveRecord::Migration
def change
create_join_table :restaurants, :users do |t|
# t.index [:restaurant_id, :user_id]
# t.index [:user_id, :restaurant_id]
end
end
end
If you want to index these columns, uncomment the respective lines and you're good to go!
When creating the join table, pay careful attention to the requirement that the two tables need to be listed in alphabetical order in the migration name/class. This can easily bite you if your model names are similar, e.g. "abc" and "abb". If you were to run
rails g migration create_abc_abb_table
Your relations will not work as expected. You must use
rails g migration create_abb_abc_table
instead.
For HABTM relationships, you need to create a join table. There is only join table and that table should not have an id column. Try this migration.
def self.up
create_table :restaurants_users, :id => false do |t|
t.integer :restaurant_id
t.integer :user_id
end
end
def self.down
drop_table :restaurants_users
end
You must check this relationship rails guide tutorials

id field without autoincrement option in migration

I have a DB migration like so:
class CreateParticipations < ActiveRecord::Migration
def self.up
create_table(:participations, :primary_key => 'Seat') do |t|
t.integer :Seat
t.string :Nickname
t.string :Clan
t.string :FirstName
t.string :LastName
t.string :Email
t.boolean :Payed
t.timestamps
end
end
def self.down
drop_table :participations
end
end
Now, seat is created with an Auto increment. However, I do not want that. I want it without an auto increment. I will define Seat myself in my Logic.
I have been looking around but I cannot find how to disable auto_increment.
How do I do this? Except for manually doing it in MySQL.
For the record, if you absolutely need to do this (it shouldn't happen often), here's the way to do a non-autoincrementing primary key with the Rails migration DSL:
create_table(:table_name, :id => false) do |t|
t.integer :id, :options => 'PRIMARY KEY'
end
That will work for MySQL anyway, if your DB uses different syntax to specify a primary key, replace the :options => 'PRIMARY KEY' with whatever that is.
This question is 3 years old, but incase anyone is wondering 3 years later, like I was, all you do is "change_column" in the event the table is already created:
change_column(:table_name, :id, :integer, :null => false)
This should work in Rails 2.x and 3.x.
O
Not saying its a good idea, but here's how I did it for SQLite3 - just replace that SQLiteAdapter with your DB's adapter - you might do this cleaner/short with a call to define_method
class AbstractAdapter
end
module ActiveRecord
module ConnectionAdapters
class SQLiteAdapter < AbstractAdapter
def supports_autoincrement?
false
end
end
end
end
<then you migration>
or
class SomeMigration < ActiveRecord::Migration
def change
create_table :table do |t|
ActiveRecord::ConnectionAdapters::SQLiteAdapter.send :define_method, :supports_autoincrement? do false end
t.integer etc
end
end
end
Of course just change the adapter for other db's
Is there a reason you can't use rails' id key and manually add an index called Seat?
I've seen some hacks just to get rails to -work- on non-increment-pk databases. I don't think it's an option. If I recall, that's how rails accesses all its per-row functionality.
Honestly, how -absolutely- do you need that slight boost in efficiency of ignoring rails' structure?
I think the real answer is "you can't." Activerecord has a few things it will not bend on.

Resources