Inspecting Model Relationships from the Rails Console
Problem
You want to inspect the relationships between the objects in your model to confirm you have them set up correctly. You could do this by dummying up a web application, but you want something quick and simple, and nothing beats the command line.
Solution
Use the Rails console to create objects of your models and to explore their relationships with one another.
From your project root, type:
~/projects$ ruby script/console -s
Loading development environment in sandbox.
Any modifications you make will be rolled back on exit.
If you're using Windows, use:
C:\myApp>ruby script/console -s
You are then put into an irb session with full access to your project environment and its Active Record models. You can enter Ruby code, just as you would in a controller, to find any problems with your data model.
Discussion
As a demonstration, create a database for a project that tracks assets and their types. This example also associates assets with tags. Create this database by generating three models using script/generate: asset, asset_type, and tag. (Note that you don't want a model for the assets_tags association table because Rails handles it internally.)
~/project$ ruby script/generate model asset
...
~/project$ ruby script/generate model asset_type
...
~/project$ ruby script/generate model tag
...
Now, define the specific table definitions with the following migration:
class BuildDb < ActiveRecord::Migration
def self.up
create_table :asset_types do |t|
t.column :name, :string
end
create_table :assets do |t|
t.column :asset_type_id, :integer
t.column :name, :string
t.column :description, :text
end
create_table :tags do |t|
t.column :name, :string
end
create_table :assets_tags do |t|
t.column :asset_id, :integer
t.column :tag_id, :integer
end
end
def self.down
drop_table :assets_tags
drop_table :assets
drop_table :asset_types
drop_table :tags
end end
Next, you can populate the database with some dummy data. Use the following SQL insert statements for this:
insert into asset_types values (1,'Photo');
insert into asset_types values (2,'Painting');
insert into asset_types values (3,'Print');
insert into asset_types values (4,'Drawing');
insert into asset_types values (5,'Movie');
insert into asset_types values (6,'CD');
insert into assets values (1,1,'Cypress','A photo of a tree.');
insert into assets values (2,5,'Blunder','An action film.');
insert into assets values (3,6,'Snap','A recording of a fire.');
insert into tags values (1,'hot');
insert into tags values (2,'red');
insert into tags values (3,'boring');
insert into tags values (4,'tree');
insert into tags values (5,'organic');
insert into assets_tags values (1,4);
insert into assets_tags values (1,5);
insert into assets_tags values (2,3);
insert into assets_tags values (3,1);
insert into assets_tags values (3,2);
Now set up the relationships between the models. This example includes a one-to-many and a many-to-many relationship.
asset_type.rb:
class AssetType < ActiveRecord::Base
has_many :assets end
tag.rb:
class Tag < ActiveRecord::Base
has_and_belongs_to_many :assets end
asset.rb:
class Asset < ActiveRecord::Base
belongs_to :asset_type
has_and_belongs_to_many :tags end
Now that we've got the model set up and have some data loaded, we can open a console session and have a look around:
~/project$ ruby script/console -s
Loading development environment in sandbox.
Any modifications you make will be rolled back on exit.
>> a = Asset.find(3)
=> #<Asset:0x4093fba8 @attributes={"name"=>8220;Snap", "id"=>"3",
"asset_type_id"=>"6", "description"=>"A recording of a fire."}>
>> a.name
=> "Snap"
>> a.description
=> "A recording of a fire."
>> a.asset_type
=> #<AssetType:0x4093a090 @attributes={"name"=>"CD", "id"=>"6"}>
>> a.asset_type.name
=> "CD"
>> a.tags
=> [#<Tag:0x40935acc @attributes={"name"=>"hot", "tag_id"=>"1", "id"=>"1",
"asset_id"=>"3"}>, #<Tag:0x40935a90 @attributes={"name"=>"red", "tag_id"=>"2",
"id"=>"2", "asset_id"=>"3"}>]
>> a.tags.each { |t| puts t.name }
hot red
=> [#<Tag:0x40935acc @attributes={"name"=>"hot", "tag_id"=>"1", "id"=>"1",
"asset_id"=>"3"}>, #<Tag:0x40935a90 @attributes={"name"=>"red", "tag_id"=>"2",
"id"=>"2", "asset_id"=>"3"}>]
In the console session, we retrieve the asset record with an ID of 3 and store it in an object. We display the asset's name and description. Fetching the asset's type returns an AssetType object. The next line returns the name of that asset type.
Accessing the tags of this asset object returns an array consisting of the asset's tags. The next command iterates over these tags and prints each tag name.
As objects become larger and more complex, their printed representation in the console can become quite difficult to read. Printing model objects to the console with pp (pretty-print) or y (yaml) can greatly improve the readability of the information. Try the following commands in the console:
require 'pp'
asset = Asset.find(:first)
pp asset y asset
The y method prints the object in YAML format and is really just a shortcut for:
puts asset.to_yaml
Examining your model in this stripped-down environment is a great way to make sure that there are no problems. Doing similar testing within the controllers of your application
could make an obvious
problem a little harder to find.
See Also
|