Migrations From Custom Generator Don't Migrate - ruby-on-rails

I am creating a gem
I have a generator to create a migration based on a name of your choosing
rails g my_generator MODEL
I am not using rails'
rails g migration XYZ
But instead pretty much copying what a schema would look like...example: if a user types the following
rails g my_generator Item
You get:
class CreateItem < ActiveRecord::Migration
def change
create_table "items", force: true do |t|
t.string "title"
t.integer "color_id"
t.integer "size_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "base_product_id"
t.integer "stock_qty"
end
end
end
The name of the migration is (my_generator)create_items.rb I have not inserted the timestamp in the start of the migration. That is really the only difference between a rails g model Item's migration, and the one I get from my generator.
My migration doesn't do anything, but I tested creating a new model, and running rake db:migrate, the rails g model migrates, mine does not.
Here is my generator:
class Rails::ShiftedCommerceGenerator < Rails::Generators::NamedBase
def create_main_model
create_file "app/models/shifted_commerce/#{plural_name.singularize}.rb", <<-FILE
class #{class_name} < ActiveRecord::Base
belongs_to :base_#{plural_name.singularize}
has_many :line_items
belongs_to :size
belongs_to :color
validates_uniqueness_of :base_#{plural_name.singularize}_id, :scope => [:size_id]
def is_base_#{plural_name.singularize}?
return true if self.class.name == "Base#{class_name}"
end
def is_#{plural_name.singularize}?
return true if self.class.name == "#{class_name}"
end
def in_stock
self.stock_qty > 0
end
end
FILE
end
def create_main_migration
create_file "db/migrate/shifted_commerce_create_#{plural_name}.rb", <<-FILE
class Create#{class_name} < ActiveRecord::Migration
def change
create_table :#{plural_name}, force: true do |t|
t.string :title
t.integer :color_id
t.integer :size_id
t.datetime :created_at
t.datetime :updated_at
t.integer :base_product_id
t.integer :stock_qty
t.timestamps
end
end
end
FILE
end
end

Make sure you include the timestamp when you are generating your own migrations
(not using rails g migration)
Your generator should include something this:
create_file "db/migrate/#{Time.now.strftime("%Y%m%d%H%M%S")}_create_#{plural_name}.rb", <<-FILE
the .strftime method is a way to get the timestamp into your migration file the same way rails has it formatted.

Related

"TypeError: no implicit conversion of nil into String" on HABTM association

I have to deal with this error when I try to associate a record to another one via a HABTM association:
Person.first.communities = Communities.all
Models and migrations:
class CreatePeople < ActiveRecord::Migration
def change
create_table :people do |t|
t.string :name
t.string :email
t.timestamps null: false
end
end
end
class CreateCommunities < ActiveRecord::Migration
def change
create_table :communities do |t|
t.string :name
t.text :description
t.timestamps null: false
end
end
end
class CreateJoinTablePersonCommunity < ActiveRecord::Migration
def change
create_join_table :people, :communities do |t|
# t.index [:person_id, :community_id]
# t.index [:community_id, :person_id]
end
end
end
I use the pg (0.18.4) gem with the Postgres (9.5.2)
Youcan use below code to create relationship.
Person.first.communities << Communities.all
If this not works please check your associations via reflect association method on the model.

Error on generate scaffolds with references

I'm trying to generate 3 scaffolds:
$ rails g scaffold Artist name:string type:string bio:text resume:string
site:string
$ rails g scaffold ArtistSerie title:string artist:references
$ rails g scaffold ArtistSeriePhoto photo:string
title:string year:integer description:text dimensions:string
featured:boolean artist_serie:references
the first two models are creating their indexes and foreign keys properly, but the third one is generating this error after rake db:migrate:
Mysql2::Error: Key column 'artist_series_id' doesn't exist in table: ALTER TABLE `artist_serie_photos` ADD CONSTRAINT `fk_rails_9422e9e931`
FOREIGN KEY (`artist_series_id`)
REFERENCES `artist_series` (`id`)
here is the generated migrations:
class CreateArtists < ActiveRecord::Migration
def change
create_table :artists do |t|
t.string :name
t.string :type
t.text :bio
t.string :resume
t.string :site
t.timestamps null: false
end
end
end
class CreateArtistSeries < ActiveRecord::Migration
def change
create_table :artist_series do |t|
t.string :title
t.references :artist, index: true, foreign_key: true
t.timestamps null: false
end
end
end
class CreateArtistSeriePhotos < ActiveRecord::Migration
def change
create_table :artist_serie_photos do |t|
t.string :photo
t.string :title
t.integer :year
t.text :description
t.string :dimensions
t.boolean :featured
t.references :artist_serie, index: true, foreign_key: true
t.timestamps null: false
end
end
end
the table was created and the field artist_serie_id too but the index and foreign key don't.
I already created another blank project and it works (on sqlite) so probably it's a mysql adapter error.
Any idea?
I appreciate your help!
I expect the root problem is that series is singular. That is, serie is not the singular form of series. It might be worth replacing series with sequence.

Simple association issue with rails and not working

Here is my Schema file
ActiveRecord::Schema.define(version: 20150917104809) do
create_table "customers", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
end
create_table "orders", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "order_date"
t.integer "customers_id"
end
end
Here are the models
class Customer < ActiveRecord::Base
has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
belongs_to :customer
end
The migration file for association is
class AddForeignKeyToOrders < ActiveRecord::Migration
def change
add_reference :orders, :customers
end
end
Following the simple rails assoc example in the link
I created a customer record using the command
Customer.create(name: 'Someone')
and now trying to create the order
#order = #customer.orders.create(order_date: Time.now)
Am getting an error with a NilClass
NoMethodError: undefined method `orders' for nil:NilClass
May be another pair of eyes of help to tell what am I doing wrong.
You need to assign the return value of create to #customer:
#customer = Customer.create(name: 'Someone')
#order = #customer.orders.create(order_date: Time.now)
It also looks like you have a typo in your schema. It should be:
t.integer "customer_id"
EDIT: Your migration file is incorrect. It should be:
class AddForeignKeyToOrders < ActiveRecord::Migration
def change
add_reference :orders, :customer
end
end
See the add_reference API docs.
To add to #ghr's answer, your error is thus: for nil:NilClass
This means that you're trying to call a method on an object which doesn't exist. Ruby actually assigns nil classes to an NilClass object, so it's errors aren't easily recognized unless you've spent time with them.
--
You have to assign Customer.create... to a variable, otherwise Rails doesn't have the data stored for you to work with:
#customer = Customer.create(name: "Someone")
#customer.orders.create
As a note, you don't need order_date in your Order model - created_at will handle that. If you removed the order_date column from your table, you'd be able to call the following:
#app/models/order.rb
class Order < ActiveRecord::Base
belongs_to :customer
alias_attribute :date, :created_at
end
#customer.orders.first.date

Index's not being created

I am trying to create a user_roles table in my engine that joins the user with a particular role allowing that user to have one or more roles.
I have the following migrations:
User
-- This migration works fine.
class CreateXaaronUsers < ActiveRecord::Migration
def change
create_table :xaaron_users do |t|
t.string :first_name
t.string :last_name
t.string :user_name
t.string :email
t.string :password
t.string :salt
t.timestamps
end
end
end
Roles
-- This migration works fine
class Roles < ActiveRecord::Migration
def change
create_table :xaaron_roles do |t|
t.string :role
t.timestamps
end
end
end
user_roles
-- This migration explodes stating that column user_id doesn't exist. I assume that this migration, dealing with indexes and the such, would create the appropriate columns referencing what I am telling it to reference.
class UserRolesJoin < ActiveRecord::Migration
def change
create_table :xaaron_user_roles, id: false do |t|
t.references :xaaron_user, null: false
t.references :xaaron_role, null: false
end
add_index :xaaron_user_roles, :user_id
add_index :xaaron_user_roles, [:role_id, :user_id], unique: true
add_index :xarron_roles, :role, unique: true
end
end
The exact error is:
PG::UndefinedColumn: ERROR: column "user_id" does not exist
: CREATE INDEX "index_xaaron_user_roles_on_user_id" ON "xaaron_user_roles" ("user_id")/Users/Adam/.rvm/gems/ruby-2.0.0-p353/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `async_exec'
/Users/Adam/.rvm/gems/ruby-2.0.0-p353/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `block in execute''
Did I fail at typing something? Why is this migration failing, aside from the obvious?
If you just want to create a join table then,
1. Remove the existing migration
rails d migration UserRolesJoin
2. Create a new migration for join table as
rails g migration CreateJoinTableUserRole user role
This will create a migration like:
class CreateJoinTableUserRole < ActiveRecord::Migration
def change
create_join_table :users, :roles do |t|
# t.index [:user_id, :role_id]
# t.index [:role_id, :user_id]
end
end
end
NOTE: You need to uncomment one of the combination as per your requirement from the generated migration.
3. Run rake db:migrate

rails generate migration add_index_to... does not put the actual index in the migration file

I created a users table via "rails generate model User name:string email:string ..." the migration file was created as well.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
Now I want to add an index to the email column "following the tutorial" I've done this successfully the first time through using sqlite3. Second time through im using MySql (mysql2). Again created the table fine with generate model.. When I run the following:
rails generate migration add_index_to_users_email
the process ends with no error message and creates the migration file as shown below, but there is no setting of any index..
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
end
end
Im expecting to see add_index :users, :email, unique: true in there ... Anybody have any idea's.. searched other threads to no avail.. running rails 4, mysql 5.6 ruby 1.9.3 my schema that was created after initil db:migrate is:
ActiveRecord::Schema.define(version: 20131024161033) do
create_table "users", force: true do |t|
t.string "name"
t.string "email"
t.string "city"
t.string "state"
t.string "zip"
t.string "mobile_phone"
t.string "mobile_phone_type"
t.date "birth_date"
t.string "user_type"
t.string "ss_num"
t.boolean "agree_to_terms"
t.datetime "created_at"
t.datetime "updated_at"
end
end
via http://guides.rubyonrails.org/migrations.html
If you'd like to add an index on the new column, you can do that as
well:
$ rails generate migration AddPartNumberToProducts
part_number:string:index
your generator
rails generate migration add_index_to_users_email
simply creates an empty migration file and did not describe a index
so this would be more appropriate...
rails generate migration AddIndexToUsers email:string:index
should give you
class AddIndexToUsers < ActiveRecord::Migration
def change
add_index :users, :email
end
end
Nguyen You - EDIT
This command [Rails 5.2.3]
rails generate migration AddIndexToUsers email:string:index
actually will give you
class AddIndexToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :email, :string
add_index :users, :email
end
end
not only add_index but also add_column to the users table.
rails generate migration AddIndexToUsers email:string:index
if you already have column it just add index, like:
class AddIndexToUsers < ActiveRecord::Migration
def change
add_index :users, :email
end
end
if you create new column (you haven't got column in database yet), it returns:
class AddIndexToUsers < ActiveRecord::Migration
def change
add_column :user, :email, :string
add_index :users, :email
end
end
From the http://railstutorial.ru/chapters/4_0/modeling-users#code-email_uniqueness_index.
The email uniqueness migration is not pre-defined, so we need to fill in its contents with this by ourself " add_index :users, :email, unique: true " .
The result will be:
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
end
end

Resources