ActiveRecord
Creating a Model manually
While using scaffolding is a fast and easy if you are new to Rails or you are creating a new application, later it can be useful just to do it on your own ato avoid the need to go through the scaffold-generated code to slim it down (remove unused parts, etc.).
Creating a model can be as simple as creating a file under app/models
.
The most simple model, in ActiveRecord
, is a class that extends ActiveRecord::Base
.
class User < ActiveRecord::Base
end
Model files are stored in app/models/
, and the file name corresponds to the singular name of the class:
# user
app/models/user.rb
# SomeModel
app/models/some_model.rb
The class will inherit all the ActiveRecord features: query methods, validations, callbacks, etc.
# Searches the User with ID 1
User.find(1)
Note: Make sure that the table for the corresponding model exists. If not, you can create the table by creating a Migration
You can generate a model and it’s migration by terminal from the following command
rails g model column_name1:data_type1, column_name2:data_type2, ...
and can also assign foreign key(relationship) to the model by following command
rails g model column_name:data_type, model_name:references
Creating a Model via generator
Ruby on Rails provides a model
generator you can use to create ActiveRecord models. Simply use rails generate model
and provide the model name.
$ rails g model user
In addition to the model file in app/models
, the generator will also create:
- the Test in
test/models/user_test.rb
- the Fixtures in
test/fixtures/users.yml
- the database Migration in
db/migrate/XXX_create_users.rb
You can also generate some fields for the model when generating it.
$ rails g model user email:string sign_in_count:integer birthday:date
This will create the columns email, sign_in_count and birthday in your database, with the appropriate types.
Creating A Migration
Add/remove fields in existing tables
Create a migration by running:
rails generate migration AddTitleToCategories title:string
This will create a migration that adds a title
column to a categories
table:
class AddTitleToCategories < ActiveRecord::Migration[5.0]
def change
add_column :categories, :title, :string
end
end
Similarly, you can generate a migration to remove a column: rails generate migration RemoveTitleFromCategories title:string
This will create a migration that removes a title
column from the categories
table:
class RemoveTitleFromCategories < ActiveRecord::Migration[5.0]
def change
remove_column :categories, :title, :string
end
end
While, strictly speaking, specifying type (:string
in this case) is not necessary for removing a column, it’s helpful, since it provides the information necessary for rolling it back.
Create a table
Create a migration by running:
rails g CreateUsers name bio
Rails recognizes the intent to create a table from the Create
prefix, the rest of the migration name will be used as a table name. The given example generates the following:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :bio
end
end
end
Notice that the creation command didn’t specify types of columns and the default string
was used.
Create a join table
Create a migration by running:
rails g CreateJoinTableParticipation user:references group:references
Rails detects the intent to create a join table by finding JoinTable
in migration name. Everything else is determined from the names of the fields you give after the name.
class CreateJoinTableParticipation < ActiveRecord::Migration
def change
create_join_table :users, :groups do |t|
# t.index [:user_id, :group_id]
# t.index [:group_id, :user_id]
end
end
end
Uncomment the necessary index
statements and delete the rest.
Precedence
Notice that the example migration name CreateJoinTableParticipation
matches the rule for table creation: it has a Create
prefix. But it did not generate a simple create_table
. This is because migration generator (source code) uses a first match of the following list:
-
(Add|Remove)<ignored>(To|From)<table_name>
-
<ignored>JoinTable<ignored>
-
Create<table_name>
Introduction to Callbacks
A callback is a method that gets called at specific moments of an object’s lifecycle (right before or after creation, deletion, update, validation, saving or loading from the database).
For instance, say you have a listing that expires within 30 days of creation.
One way to do that is like this:
class Listing < ApplicationRecord
after_create :set_expiry_date
private
def set_expiry_date
expiry_date = Date.today + 30.days
self.update_column(:expires_on, expiry_date)
end
end
All of the available methods for callbacks are as follows, in the same order that they are called during the operation of each object:
Creating an Object
- before_validation
- after_validation
- before_save
- around_save
- before_create
- around_create
- after_create
- after_save
- after_commit/after_rollback
Updating an Object
- before_validation
- after_validation
- before_save
- around_save
- before_update
- around_update
- after_update
- after_save
- after_commit/after_rollback
Destroying an Object
- before_destroy
- around_destroy
- after_destroy
- after_commit/after_rollback
NOTE: after_save runs both on create and update, but always after the more specific callbacks after_create and after_update, no matter the order in which the macro calls were executed.
Create a Join Table using Migrations
Specially useful for has_and_belongs_to_many
relation, you can manually create a join table using the create_table
method.
Suppose you have two models Tags
and Proyects
, and you’d like to associate them using a has_and_belongs_to_many
relation. You need a join table to associate instances of both classes.
class CreateProjectsTagsJoinTableMigration < ActiveRecord::Migration
def change
create_table :projects_tags, id: false do |t|
t.integer :project_id
t.integer :tag_id
end
end
end
The actual name of the table needs to follow this convention: the model which alphabetically precedes the other must go first. Project preceds Tags so the name of the table is projects_tags.
Also since the purpose of this table is to route the association between the instances of two models, the actual id of every record in this table is not necessary. You specify this by passing id: false
Finally, as is convention in Rails, the table name must be the compound plural form of the individual models, but the column of the table must be in singular form.
Manually Testing Your Models
Testing your Active Record models through your command line interface is simple.
Navigate to the app directory in your terminal and type in rails console
to start the Rails console. From here, you can run active record methods on your database.
For example, if you had a database schema with a Users table having a name:string
column and email:string
, you could run:
User.create name: "John", email: "john@example.com"
Then, to show that record, you could run:
User.find_by email: "john@example.com"
Or if this is your first or only record, you could simply get the first record by running:
User.first