Recently I have started exploring Phoenix as part of my learning. Phoenix is a web framework just like Rails but it built on top of Elixir and Ecto is an ORM just like Active Record use by Phoenix to talk to DB.

Since the semantics of Phoenix is similar to rails makes me very comfortable with Phoenix. Let see some similarities between Ecto and Active Record. Prior to that, the important aspect about Ecto is it follows Explicitness whereas Active Record follows implicitness. Let check out these characteristics with examples:

  1. Model Generation

In Active Record

rails g model User first_name:string last_name:string
# app/models/user.rb
class User < ApplicationRecord
end
# db/migrate/20170925112416_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.1]
  def change
    create_table :users do |t|
      t.string :first_name
      t.string :last_name
      t.timestamps
    end
  end
end

In Ecto

mix phx.gen.scheme User users first_name:string last_name:string
# lib/stc/user.ex
defmodule Stc.User do
 use Ecto.Schema
 import Ecto.Changeset
 alias Stc.User
 schema “users” do
   field :first_name, :string
   field :last_name, :string
   timestamps()
 end
end
# priv/repo/migrations/20170925112137_create_user.exs
defmodule Stc.Repo.Migrations.CreateUser do
 use Ecto.Migration
 def change do
   create table(:user) do
     add :first_name, :string
     add :last_name, :string
     timestamps()
   end
end

Unlike Active Record, in Ecto, we have to mention schema to access necessary attributes from a table. Otherwise, Ecto returns only those fields that are defined in the schema.
In Active Record when you mention User, implicitly it understands that it should talk with users table. Whereas in Ecto if you mention schema as the userfor the Usermodel then it talks to the tableuser instead of.users

2. Querying:

In Active Record

# To insert single record
> User.create(first_name: ‘siva’, last_name: ‘Gollapalli’)
# To Fetch all records
> User.all

In Ecto

# To insert single record
> %Stc.User{first_name: “Siva”, last_name: “Gollapalli”} |> Stc.Repo.insert
# To Fetch all records
> Stc.User |> Stc.Repo.all

In Ecto, querying will be handled by a module called Repo which is an OTP app. By DB config, it knows which DB it should talk but to query a table we should explicitly pass the table name to Repo to get query result as above.

3. Associations:

In Active Record

class User < ApplicationRecord
  has_many :posts
end
class Post < ApplicationRecord
  belongs_to :user
end
> user = User.first
> post = Post.create(description: "associations", user: user)
# To Fetch all posts of a user
> user.posts

In Ecto

# lib/stc/user.ex
defmodule Stc.User do
 use Ecto.Schema
 import Ecto.Changeset
 alias Stc.User
 schema "users" do
   has_many :posts, Stc.Post
 end
end
# lib/stc/post.ex
defmodule Stc.Post do
 use Ecto.Schema
 import Ecto.Changeset
 alias Stc.Post
schema "posts" do
   field :description, :string
   belongs_to :user, Stc.user
 end
end
> user = Stc.Repo.get(Stc.User, 1)
> Ecto.build_assoc(user, 
                  :posts, 
                  %{description: "First post"}) |> Stc.Repo.insert
# To Fetch all posts of a user
> Stc.Repo.all assoc(user, :posts)

As we know that in Rails, depends upon the relationship, AR would find respective model unless and until if relationship defers from the model name. If it differs then we explicitly pass an option called inclass_name relation.

In Ecto, it follows the same pattern but by default. As you see we are explicitly mentioning module name while defining a relation.

Though for the users coming from Rails background might face hiccups in their baby steps but as you progress it gives a better understanding.

Thanks for reading. Any suggestions would be welcome!!!.