Merge branch 'master' of github.com:lifo/docrails
This commit is contained in:
commit
62f865db0b
@ -287,7 +287,7 @@ def touch(name = nil)
|
||||
|
||||
private
|
||||
|
||||
# A hook to be overriden by association modules.
|
||||
# A hook to be overridden by association modules.
|
||||
def destroy_associations
|
||||
end
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 118 KiB |
@ -216,6 +216,8 @@ If you follow this guide, you'll create a Rails project called <tt>blog</tt>, a
|
||||
(very) simple weblog. Before you can start building the application, you need to
|
||||
make sure that you have Rails itself installed.
|
||||
|
||||
TIP: The examples below use # and $ to denote terminal prompts. If you are using Windows, your prompt will look something like c:\source_code>
|
||||
|
||||
h4. Installing Rails
|
||||
|
||||
In most cases, the easiest way to install Rails is to take advantage of RubyGems:
|
||||
@ -246,7 +248,8 @@ $ rails new blog
|
||||
This will create a Rails application called Blog in a directory called blog.
|
||||
|
||||
TIP: You can see all of the switches that the Rails application builder accepts
|
||||
by running <tt>rails new -h</tt>.
|
||||
by running
|
||||
<tt>rails new -h</tt>.
|
||||
|
||||
After you create the blog application, switch to its folder to continue work
|
||||
directly in that application:
|
||||
@ -278,18 +281,6 @@ by default:
|
||||
|tmp/|Temporary files|
|
||||
|vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.|
|
||||
|
||||
h4. Installing the Required Gems
|
||||
|
||||
Rails applications manage gem dependencies with
|
||||
"Bundler":http://gembundler.com/v1.0/index.html by default. As we don't need any
|
||||
other gems beyond the ones in the generated +Gemfile+ we can directly run
|
||||
|
||||
<shell>
|
||||
$ bundle install
|
||||
</shell>
|
||||
|
||||
to have them ready.
|
||||
|
||||
h4. Configuring a Database
|
||||
|
||||
Just about every Rails application will interact with a database. The database
|
||||
@ -405,12 +396,12 @@ development:
|
||||
|
||||
Change the username and password in the +development+ section as appropriate.
|
||||
|
||||
TIP: You don't have to update the database configurations manually. If you had a
|
||||
look at the options of application generator, you have seen that one of them is
|
||||
named <tt>--database</tt>. It lets you choose an adapter for couple of most used
|
||||
relational databases. You can even run the generator repeatedly: <tt>cd .. &&
|
||||
rails new blog --database=mysql</tt>. When you confirm the overwriting of the
|
||||
+config/database.yml+ file, your application will be configured for MySQL
|
||||
TIP: You don't have to update the database configurations manually. If you look at the
|
||||
options of the application generator, you will see that one of the options
|
||||
is named <tt>--database</tt>. This option allows you to choose an adapter from a
|
||||
list of the most used relational databases. You can even run the generator
|
||||
repeatedly: <tt>cd .. && rails new blog --database=mysql</tt>. When you confirm the overwriting
|
||||
of the +config/database.yml+ file, your application will be configured for MySQL
|
||||
instead of SQLite.
|
||||
|
||||
h4. Creating the Database
|
||||
@ -470,8 +461,8 @@ your terminal:
|
||||
$ rails generate controller home index
|
||||
</shell>
|
||||
|
||||
TIP: If you're on Windows, or your Ruby is set up in some non-standard fashion,
|
||||
you may need to explicitly pass Rails +rails+ commands to Ruby: <tt>ruby
|
||||
TIP: If you get a command not found error when running this command, you
|
||||
need to explicitly pass Rails +rails+ commands to Ruby: <tt>ruby
|
||||
\path\to\your\application\script\rails generate controller home index</tt>.
|
||||
|
||||
Rails will create several files for you, including
|
||||
|
@ -477,7 +477,7 @@ Several methods are provided that allow you to control all this:
|
||||
|
||||
For example, this migration
|
||||
|
||||
<ruby>
|
||||
<pre>
|
||||
class CreateProducts < ActiveRecord::Migration
|
||||
def change
|
||||
suppress_messages do
|
||||
@ -496,7 +496,7 @@ class CreateProducts < ActiveRecord::Migration
|
||||
end
|
||||
end
|
||||
end
|
||||
</ruby>
|
||||
</pre>
|
||||
|
||||
generates the following output
|
||||
|
||||
@ -514,40 +514,107 @@ If you just want Active Record to shut up then running +rake db:migrate VERBOSE=
|
||||
|
||||
h3. Using Models in Your Migrations
|
||||
|
||||
When creating or updating data in a migration it is often tempting to use one of your models. After all they exist to provide easy access to the underlying data. This can be done but some caution should be observed.
|
||||
When creating or updating data in a migration it is often tempting to use one of your models. After all they exist to provide easy access to the underlying data. This can be done, but some caution should be observed.
|
||||
|
||||
Consider for example a migration that uses the +Product+ model to update a row in the corresponding table. Alice later updates the +Product+ model, adding a new column and a validation on it. Bob comes back from holiday, updates the source and runs outstanding migrations with +rake db:migrate+, including the one that used the +Product+ model. When the migration runs the source is up to date and so the +Product+ model has the validation added by Alice. The database however is still old and so does not have that column and an error ensues because that validation is on a column that does not yet exist.
|
||||
For example, problems occur when the model uses database columns which are (1) not currently in the database and (2) will be created by this or a subsequent migration.
|
||||
|
||||
Frequently I just want to update rows in the database without writing out the SQL by hand: I'm not using anything specific to the model. One pattern for this is to define a copy of the model inside the migration itself, for example:
|
||||
Consider this example, where Alice and Bob are working on the same code base which contains a +Product+ model:
|
||||
|
||||
<ruby>
|
||||
class AddPartNumberToProducts < ActiveRecord::Migration
|
||||
class Product < ActiveRecord::Base
|
||||
end
|
||||
Bob goes on vacation.
|
||||
|
||||
Alice creates a migration for the +products+ table which adds a new column and initializes it.
|
||||
She also adds a validation to the Product model for the new column.
|
||||
|
||||
<pre>
|
||||
# db/migrate/20100513121110_add_flag_to_product.rb
|
||||
|
||||
class AddFlagToProduct < ActiveRecord::Migration
|
||||
def change
|
||||
...
|
||||
add_column :products, :flag, :int
|
||||
Product.all.each { |f| f.update_attributes!(:flag => 'false') }
|
||||
end
|
||||
end
|
||||
</ruby>
|
||||
The migration has its own minimal copy of the +Product+ model and no longer cares about the +Product+ model defined in the application.
|
||||
</pre>
|
||||
|
||||
h4. Dealing with Changing Models
|
||||
<pre>
|
||||
# app/model/product.rb
|
||||
|
||||
For performance reasons information about the columns a model has is cached. For example if you add a column to a table and then try and use the corresponding model to insert a new row it may try to use the old column information. You can force Active Record to re-read the column information with the +reset_column_information+ method, for example
|
||||
class Product < ActiveRecord::Base
|
||||
validates_presence_of :flag
|
||||
end
|
||||
</pre>
|
||||
|
||||
<ruby>
|
||||
class AddPartNumberToProducts < ActiveRecord::Migration
|
||||
Alice adds a second migration which adds and initializes another column to the +products+ table and also adds a validation to the Product model for the new column.
|
||||
|
||||
<pre>
|
||||
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
||||
|
||||
class AddFuzzToProduct < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :products, :fuzz, :string
|
||||
Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
# app/model/product.rb
|
||||
|
||||
class Product < ActiveRecord::Base
|
||||
validates_presence_of :flag
|
||||
validates_presence_of :fuzz
|
||||
end
|
||||
</pre>
|
||||
|
||||
Both migrations work for Alice.
|
||||
|
||||
Bob comes back from vacation and:
|
||||
|
||||
# updates the source - which contains both migrations and the latests version of the Product model.
|
||||
# runs outstanding migrations with +rake db:migrate+, which includes the one that updates the +Product+ model.
|
||||
|
||||
The migration crashes because when the model attempts to save, it tries to validate the second added column, which is not in the database when the _first_ migration runs.
|
||||
|
||||
<pre>
|
||||
rake aborted!
|
||||
An error has occurred, this and all later migrations canceled:
|
||||
|
||||
undefined method `fuzz' for #<Product:0x000001049b14a0>
|
||||
</pre>
|
||||
|
||||
A fix for this is to create a local model within the migration. This keeps rails from running the validations, so that the migrations run to completion.
|
||||
|
||||
When using a faux model, it's a good idea to call +Product.reset_column_information+ to refresh the ActiveRecord cache for the Product model prior to updating data in the database.
|
||||
|
||||
If Alice had done this instead, there would have been no problem:
|
||||
|
||||
<pre>
|
||||
# db/migrate/20100513121110_add_flag_to_product.rb
|
||||
|
||||
class AddFlagToProduct < ActiveRecord::Migration
|
||||
class Product < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def change
|
||||
add_column :product, :part_number, :string
|
||||
add_column :products, :flag, :int
|
||||
Product.reset_column_information
|
||||
Product.all.each { |f| f.update_attributes!(:flag => false) }
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
# db/migrate/20100515121110_add_fuzz_to_product.rb
|
||||
|
||||
class AddFuzzToProduct < ActiveRecord::Migration
|
||||
class Product < ActiveRecord::Base
|
||||
end
|
||||
def change
|
||||
add_column :products, :fuzz, :string
|
||||
Product.reset_column_information
|
||||
...
|
||||
Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
|
||||
end
|
||||
end
|
||||
</ruby>
|
||||
</pre>
|
||||
|
||||
|
||||
h3. Schema Dumping and You
|
||||
|
Loading…
Reference in New Issue
Block a user