I am a beginner in Ruby on Rails and following the below article:-
http://guides.rubyonrails.org/migrations.html
If I need to generate a migration and a model, I can use, for example :-
$ rails generate model Product name:string description:text
and that would create :-
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
However, If I have a bigger model (with many properties). I don't want to put all the properties in the "rails generate" command. Can I hand code the model first and then generate the migration from that model file?
Sorry for asking so stupid question. I am just trying to understand.
Generate command is not must to do thing. It's just a script which helps you to automate some job. What exactly this command has done you can see in console after running generate command. It looks like this:
rails generate scaffold User name:string email:string
invoke active_record
create
db/migrate/20100615004000_create_users.rb
create
app/models/user.rb
invoke
test_unit
create
test/unit/user_test.rb
create
test/fixtures/users.yml
route resources :users
invoke scaffold_controller
create
app/controllers/users_controller.rb
invoke
erb
create
app/views/users
create
app/views/users/index.html.erb
create
app/views/users/edit.html.erb
create
app/views/users/show.html.erb
create
app/views/users/new.html.erb
create
app/views/users/_form.html.erb
invoke
test_unit
create
test/functional/users_controller_test.rb
invoke
helper
create
app/helpers/users_helper.rb
invoke
test_unit
create
test/unit/helpers/users_helper_test.rb
invoke stylesheets
converted by Web2PDFConvert.com
create
public/stylesheets/scaffold.css
You can actually create/modify all files by your hand. But the benefit of using generate is that it automatically invokes all necessary plugins and etc to generate all required files.
That's why it's recommended to use generate command even for very complicated models, controllers and etc.
So in your case I would suggest to divide the building the model in several steps. It could be like this:
rails generate model Product name:string description:text
rails generate migration AddPriceToProducts price:integer
rails generate migration AddDiscountToProducts discount:integer
and so on
Every step you could rollback in case if you made some mistake and it helps you to not harm
your database.
You can hand-code the migration. The model's attributes are read directly from the database... so if you add t.string :name to the migration file, and then run rake db:migrate, that column will be added to the table, therefore making it available as an attribute on your model.
Related
I have an app on Heroku and need to clean up the database there, again run all (edited) migrations (in the migrations are added the default rows into the table) with the new default rows.
I ran
heroku run rake db:reset
this command cleared up the database, but didn't add the new rows into the tables. I am trying to add the new lines this way:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
...columns definitions...
t.timestamps
end
end
def self.up
Users.new(:name => 'my name', :password => 'super-secret-pass')
end
end
But the new user is not added. What am I missing?
Migrations should have one of:
A change method.
up and down methods (preferably instance methods in 3+ but class methods are fine too).
You have a change method and a self.up method. The migration system looks for change first:
ActiveRecord::Base.connection_pool.with_connection do |conn|
#connection = conn
if respond_to?(:change)
#...
else
time = Benchmark.measure { send(direction) }
end
#connection = nil
end
so your self.up will never get run.
Two solutions immediately present themselves:
Use separate up and down methods. You might want to review the guide's Using Models in Your Migrations section.
Use two separate migrations: one to create the table and a separate one to create your user.
I'd probably go with 2.
I am using FactoryGirl in my rspec2 test with rails 3.2.1 and I would like to see the FactoryGirl output especially when the test fails.
Is there a way with $stderror puts to get to view what FactoryGirl has created?
Thanks
You could use the Rails logger to write directly to your log/test.log file.
I usually add the following to spec_helper.rb
def logger
Rails::logger
end
now you can log anywhere in your spec like so:
describe Customer do
it "logs factory girl generated objects" do
customer = Factory( :customer )
logger.warn( customer.pretty_inspect )
end
end
This will print the generated customer object with all properties
I have both ActiveRecord (MySQL) and Mongoid in my Rails 3.1 application. Everything is fine, excepts all generators uses mongoid to generate models. This way, when i:
rails g model user
i receive mongoid-like model, but i need ActiveRecord structure and migrations.
How can i switch back to AR?
Mongoid overrides the model generator, but you can switch it back.
In config/application.rb you can either add a line if you've already got a block similar to this:
config.generators do |g|
g.template_engine :haml
...
g.orm :active_record
end
Or just simply add the entire config line directly to the file
config.generators.orm :active_record
You can also pass :migrations => false if you want to turn off migrations
I have a HABTM association between Users and Groups in my Rails 3 app. The book I'm following to learn Rails recommends running the following command line to create the join migration:
rails generate migration create_groups_users
However in the documentation it looks like I should've run:
rails generate migration create_groups_users_join_table
So that the following would be in my _create_groups_users.rb migration:
class CreateGroupsUsersJoinTable < ActiveRecord::Migration
Is adding join_table required?
Adding join_table at the end is not explicitly required. Your first command 'create_groups_users' is fine. I've done this in rails 3.0.9 and it works.
You can double check by opening up the migration file and checking that it looks like:
create_table :groups_users, :id => false do |t|
t.integer :group_id
t.integer :user_id
end
The :id => false is needed for a join table as it shouldn't have its own id field.
The last argument in your call to rails generate migration create_groups_users just denotes the class name and a part of the file name of the migration. So it does help to find the migration you have created, the migration file itself is (inside the class body) empty. So both versions are ok.
In rails 2 I had a lib/migration_helpers.rb file with methods for setting and dropping foreign keys in the db.
These methods were available in self.up and self.down in migration files by adding in the migration file
require 'migration_helpers'
at the top, and
extend MigrationHelpers
immediately after the class statement.
In rails 3 this does not work, and if i try to run a migration using set_foreign_key method from migration_helpers.rb the following error is thrown:
== AddFkToArticles: migrating ================================================
-- set_foreign_key("articles", "book_id", "books")
rake aborted!
An error has occurred, this and all later migrations canceled:
undefined method `set_foreign_key' for #<AddFkToArticles:0x000001034a1f38>
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
I already checked that in config/application.rb the autoload path is set to include lib.
The file is effectively required, because if i comment out the require statement then rails whines about the missing 'migration_helpers' file.
I suspect this is a scoping problem (rails 2 used "def self.up", rails 3 uses "def change")
but cannot imagine how to solve the problem (by now I simply copied the code in the migration file, just to check that it does what it should do).
Francesco
I don't know what exactly you're trying to accomplish but here's some code that might give you a clue.
## lib/test_helper.rb
module TestHelper
def my_table_name
return :mytable
end
end
And then the migration:
## db/migrate/test_migration.rb
include TestHelper
class TestMigration < ActiveRecord::Migration
def self.up
create_table my_table_name
end
def self.down
drop_table my_table_name
end
end
Including this helper inside the Migration class doesn't work so it should be outside.