Thursday

19-06-2025 Vol 19

Active Record: O Coração dos Modelos no Rails

Active Record: Jantung Model dalam Rails – Panduan Lengkap

Active Record adalah jantung dari lapisan model dalam framework Ruby on Rails. Ini adalah Object-Relational Mapping (ORM) yang menyediakan antarmuka antara basis data dan aplikasi Anda, memungkinkan Anda berinteraksi dengan data basis data menggunakan sintaks Ruby yang familiar dan intuitif. Dalam panduan lengkap ini, kita akan menjelajahi secara mendalam Active Record, mulai dari dasar-dasarnya hingga fitur-fitur canggihnya, dan bagaimana cara memanfaatkannya secara efektif dalam aplikasi Rails Anda.

Daftar Isi

  1. Pendahuluan Active Record
    • Apa itu Active Record?
    • Mengapa Menggunakan Active Record?
    • Prinsip Dasar Active Record
  2. Konfigurasi dan Koneksi Basis Data
    • Konfigurasi database.yml
    • Membuat Migrasi
    • Menjalankan Migrasi
  3. Membuat dan Menggunakan Model
    • Mendefinisikan Model
    • Atribut Model
    • Konvensi Penamaan
  4. CRUD (Create, Read, Update, Delete) dengan Active Record
    • Membuat Data (Create)
    • Membaca Data (Read)
      • Menemukan Satu Record
      • Menemukan Banyak Record
      • Kondisi WHERE
      • Operator Perbandingan
      • Operator Logika
      • Urutan (Order)
      • Limit dan Offset
    • Memperbarui Data (Update)
    • Menghapus Data (Delete)
  5. Asosiasi (Associations)
    • Jenis-jenis Asosiasi
      • belongs_to
      • has_one
      • has_many
      • has_many :through
      • has_one :through
      • has_and_belongs_to_many
    • Menggunakan Asosiasi
    • Eager Loading
  6. Validasi
    • Jenis-jenis Validasi
    • Validasi Kustom
    • Menangani Kesalahan Validasi
  7. Callback
    • Jenis-jenis Callback
    • Menggunakan Callback
  8. Scope
    • Mendefinisikan Scope
    • Menggunakan Scope
  9. Query Lanjutan dengan Active Record
    • Menggunakan joins
    • Menggunakan group
    • Menggunakan select
    • Menggunakan pluck
    • Menggunakan find_by_sql (Hati-hati!)
  10. Serialisasi
    • Menggunakan Serialisasi
  11. Polimorfisme
    • Apa itu Asosiasi Polimorfik?
    • Contoh Kasus
    • Implementasi di Rails
  12. STI (Single Table Inheritance)
    • Konsep STI
    • Implementasi STI
  13. Tips dan Praktik Terbaik
    • Optimasi Kinerja Query
    • Menghindari N+1 Query
    • Menggunakan Index
  14. Kesimpulan

1. Pendahuluan Active Record

Apa itu Active Record?

Active Record adalah lapisan ORM yang disediakan oleh Rails. Ini memfasilitasi interaksi dengan basis data dengan menyediakan representasi objek dari tabel basis data. Setiap model Active Record sesuai dengan tabel basis data, dan instance dari model tersebut mewakili baris dalam tabel tersebut. Active Record memungkinkan Anda untuk melakukan operasi CRUD (Create, Read, Update, Delete) pada data basis data menggunakan sintaks Ruby yang sederhana dan ekspresif.

Mengapa Menggunakan Active Record?

Berikut beberapa alasan mengapa menggunakan Active Record sangat bermanfaat:

  • Abstraksi Basis Data: Active Record mengabstraksi detail kompleks dari interaksi basis data, memungkinkan Anda fokus pada logika aplikasi Anda.
  • Sintaks Sederhana: Active Record menyediakan sintaks yang mudah dibaca dan dipahami untuk berinteraksi dengan basis data.
  • Portabilitas: Active Record mendukung berbagai macam sistem basis data, sehingga memudahkan untuk mengganti basis data jika diperlukan.
  • Keamanan: Active Record membantu mencegah serangan injeksi SQL dengan secara otomatis membersihkan input pengguna.
  • Konvensi over Konfigurasi: Rails, dan khususnya Active Record, menganut prinsip “konvensi over konfigurasi,” yang berarti bahwa banyak keputusan konfigurasi dibuat berdasarkan konvensi, sehingga mengurangi jumlah kode boilerplate yang perlu Anda tulis.

Prinsip Dasar Active Record

Active Record didasarkan pada beberapa prinsip dasar:

  • Model sesuai dengan tabel basis data.
  • Instance model sesuai dengan baris dalam tabel.
  • Atribut model sesuai dengan kolom dalam tabel.
  • Active Record menyediakan metode untuk melakukan operasi CRUD pada data basis data.

2. Konfigurasi dan Koneksi Basis Data

Konfigurasi database.yml

File config/database.yml adalah tempat Anda mengkonfigurasi koneksi basis data untuk aplikasi Rails Anda. File ini berisi pengaturan koneksi untuk berbagai lingkungan, seperti pengembangan, pengujian, dan produksi.

Contoh database.yml:


default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: your_username
  password: your_password

development:
  <<: *default
  database: your_app_development

test:
  <<: *default
  database: your_app_test

production:
  <<: *default
  database: your_app_production
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

Pastikan untuk mengganti your_username, your_password, your_app_development, your_app_test, dan your_app_production dengan nilai yang sesuai untuk lingkungan Anda.

Membuat Migrasi

Migrasi adalah cara untuk mengubah skema basis data Anda dari waktu ke waktu secara terstruktur dan konsisten. Anda menggunakan migrasi untuk membuat tabel, menambahkan kolom, menghapus kolom, dan melakukan perubahan lain pada struktur basis data Anda.

Untuk membuat migrasi, gunakan perintah rails generate migration:

rails generate migration CreateUsers

Perintah ini akan membuat file migrasi baru di direktori db/migrate. Anda kemudian dapat mengedit file migrasi untuk menentukan perubahan yang ingin Anda lakukan pada skema basis data Anda.

Contoh migrasi:


class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

Menjalankan Migrasi

Untuk menjalankan migrasi, gunakan perintah rails db:migrate:

rails db:migrate

Perintah ini akan menjalankan semua migrasi yang tertunda dalam urutan kronologis.

Anda juga dapat membatalkan migrasi menggunakan perintah rails db:rollback:

rails db:rollback

Perintah ini akan membatalkan migrasi terakhir yang dijalankan.

3. Membuat dan Menggunakan Model

Mendefinisikan Model

Untuk membuat model Active Record, gunakan perintah rails generate model:

rails generate model User name:string email:string

Perintah ini akan membuat file model baru di direktori app/models. Perintah ini juga akan membuat file migrasi untuk membuat tabel yang sesuai di basis data. Anda dapat menentukan tipe data untuk setiap atribut langsung di command line.

Contoh model:


class User < ApplicationRecord
end

Atribut Model

Atribut model sesuai dengan kolom dalam tabel basis data. Anda dapat mengakses atribut model menggunakan sintaks titik:


user = User.new(name: "John Doe", email: "john.doe@example.com")
puts user.name  # Output: John Doe
puts user.email # Output: john.doe@example.com

Konvensi Penamaan

Active Record menggunakan konvensi penamaan untuk menghubungkan model ke tabel basis data yang sesuai:

  • Nama model harus menggunakan singular, CamelCase (misalnya, User).
  • Nama tabel basis data harus menggunakan plural, snake_case (misalnya, users).

4. CRUD (Create, Read, Update, Delete) dengan Active Record

Membuat Data (Create)

Ada beberapa cara untuk membuat data menggunakan Active Record:

  • Menggunakan new dan save:

user = User.new(name: "Jane Doe", email: "jane.doe@example.com")
user.save

  • Menggunakan create:

user = User.create(name: "Peter Pan", email: "peter.pan@neverland.com")

  • Menggunakan create!:

user = User.create!(name: "Alice", email: "alice@wonderland.com") # Akan raise error jika validasi gagal

Metode create! akan melempar pengecualian jika validasi gagal.

Membaca Data (Read)

Ada beberapa cara untuk membaca data menggunakan Active Record:

Menemukan Satu Record

  • Menggunakan find:

user = User.find(1) # Menemukan user dengan ID 1

Metode find akan melempar pengecualian ActiveRecord::RecordNotFound jika record tidak ditemukan.

  • Menggunakan find_by:

user = User.find_by(email: "john.doe@example.com") # Menemukan user dengan email john.doe@example.com

Metode find_by akan mengembalikan nil jika record tidak ditemukan.

  • Menggunakan find_by!:

user = User.find_by!(email: "john.doe@example.com") # Menemukan user dengan email john.doe@example.com, akan raise error jika tidak ditemukan

Menemukan Banyak Record

  • Menggunakan all:

users = User.all # Mengembalikan semua user

  • Menggunakan where:

users = User.where(name: "John Doe") # Mengembalikan semua user dengan nama John Doe

Kondisi WHERE

Anda dapat menggunakan kondisi WHERE yang kompleks untuk memfilter data:


users = User.where("name LIKE ?", "%John%") # Mengembalikan semua user yang namanya mengandung "John"

Operator Perbandingan

Active Record mendukung berbagai operator perbandingan:

  • = (sama dengan)
  • != (tidak sama dengan)
  • > (lebih besar dari)
  • < (lebih kecil dari)
  • >= (lebih besar dari atau sama dengan)
  • <= (lebih kecil dari atau sama dengan)
  • LIKE (pencocokan pola)
  • IN (dalam daftar)
  • NOT IN (tidak dalam daftar)
  • IS NULL (null)
  • IS NOT NULL (tidak null)

Operator Logika

Anda dapat menggunakan operator logika untuk menggabungkan kondisi WHERE:

  • AND
  • OR
  • NOT

users = User.where(name: "John Doe").or(User.where(email: "john.doe@example.com")) # Mengembalikan user dengan nama John Doe ATAU email john.doe@example.com

Urutan (Order)

Anda dapat mengurutkan hasil query menggunakan metode order:


users = User.order(:name) # Mengurutkan user berdasarkan nama secara ascending
users = User.order(name: :desc) # Mengurutkan user berdasarkan nama secara descending

Limit dan Offset

Anda dapat membatasi jumlah record yang dikembalikan menggunakan metode limit dan offset:


users = User.limit(10) # Mengembalikan hanya 10 user pertama
users = User.offset(10).limit(10) # Mengembalikan 10 user berikutnya setelah 10 user pertama

Memperbarui Data (Update)

Ada beberapa cara untuk memperbarui data menggunakan Active Record:

  • Menggunakan update pada instance model:

user = User.find(1)
user.update(name: "Johnny Doe")

  • Menggunakan update! pada instance model:

user = User.find(1)
user.update!(name: "Jonathan Doe") # Akan raise error jika validasi gagal

  • Menggunakan update_all:

User.where(email: "john.doe@example.com").update_all(name: "Jonathan Doe") # Memperbarui semua user dengan email john.doe@example.com

Menghapus Data (Delete)

Ada beberapa cara untuk menghapus data menggunakan Active Record:

  • Menggunakan destroy pada instance model:

user = User.find(1)
user.destroy

  • Menggunakan delete pada instance model:

user = User.find(1)
user.delete # Sama seperti destroy, tapi skip callback

  • Menggunakan delete_all:

User.where(email: "john.doe@example.com").delete_all # Menghapus semua user dengan email john.doe@example.com

  • Menggunakan destroy_all:

User.where(email: "john.doe@example.com").destroy_all # Menghapus semua user dengan email john.doe@example.com dan menjalankan callback

Perbedaan penting antara delete dan destroy adalah bahwa destroy memicu callback model, sedangkan delete tidak.

5. Asosiasi (Associations)

Asosiasi adalah cara untuk menghubungkan model satu sama lain. Misalnya, seorang penulis mungkin memiliki banyak buku, dan setiap buku dimiliki oleh seorang penulis. Active Record menyediakan beberapa jenis asosiasi:

Jenis-jenis Asosiasi

  • belongs_to
  • has_one
  • has_many
  • has_many :through
  • has_one :through
  • has_and_belongs_to_many

belongs_to

Asosiasi belongs_to menunjukkan bahwa sebuah model dimiliki oleh model lain. Misalnya, model Book mungkin belongs_to model Author:


class Book < ApplicationRecord
  belongs_to :author
end

Dalam hal ini, tabel books harus memiliki kolom author_id, yang merupakan foreign key ke tabel authors.

has_one

Asosiasi has_one menunjukkan bahwa sebuah model memiliki satu instance model lain. Misalnya, model Author mungkin has_one model Profile:


class Author < ApplicationRecord
  has_one :profile
end

Dalam hal ini, tabel profiles harus memiliki kolom author_id, yang merupakan foreign key ke tabel authors.

has_many

Asosiasi has_many menunjukkan bahwa sebuah model memiliki banyak instance model lain. Misalnya, model Author mungkin has_many model Book:


class Author < ApplicationRecord
  has_many :books
end

Dalam hal ini, tabel books harus memiliki kolom author_id, yang merupakan foreign key ke tabel authors.

has_many :through

Asosiasi has_many :through menunjukkan bahwa sebuah model memiliki banyak instance model lain melalui model perantara. Misalnya, seorang dokter mungkin memiliki banyak pasien melalui janji temu:


class Doctor < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :doctors, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :doctor
  belongs_to :patient
end

has_one :through

Asosiasi has_one :through mirip dengan has_many :through, tetapi hanya mengembalikan satu instance model lain. Misalnya, seorang pemasok mungkin memiliki satu akun melalui riwayat akun:


class Supplier < ApplicationRecord
  has_one :account_history
  has_one :account, through: :account_history
end

class Account < ApplicationRecord
end

class AccountHistory < ApplicationRecord
  belongs_to :supplier
  belongs_to :account
end

has_and_belongs_to_many

Asosiasi has_and_belongs_to_many menunjukkan hubungan banyak-ke-banyak antara dua model. Misalnya, sebuah buku mungkin memiliki banyak penulis, dan seorang penulis mungkin memiliki banyak buku:


class Book < ApplicationRecord
  has_and_belongs_to_many :authors
end

class Author < ApplicationRecord
  has_and_belongs_to_many :books
end

Dalam hal ini, Anda perlu membuat tabel join bernama authors_books dengan kolom author_id dan book_id.

Menggunakan Asosiasi

Setelah Anda mendefinisikan asosiasi, Anda dapat menggunakannya untuk mengakses data terkait:


author = Author.find(1)
books = author.books # Mengembalikan semua buku yang ditulis oleh author dengan ID 1

book = Book.find(1)
author = book.author # Mengembalikan author yang menulis buku dengan ID 1

Eager Loading

Eager loading adalah teknik untuk memuat asosiasi secara efisien. Secara default, Active Record memuat asosiasi secara lambat, yang berarti bahwa asosiasi dimuat hanya ketika diakses. Ini dapat menyebabkan masalah kinerja, terutama jika Anda mengakses banyak asosiasi dalam satu tampilan. Eager loading memungkinkan Anda untuk memuat semua asosiasi yang diperlukan dalam satu query, mengurangi jumlah query basis data yang diperlukan.

Anda dapat menggunakan eager loading dengan metode includes:


authors = Author.includes(:books) # Memuat semua authors dan buku mereka dalam satu query
authors.each do |author|
  puts author.name
  author.books.each do |book|
    puts book.title
  end
end

6. Validasi

Validasi digunakan untuk memastikan bahwa data yang disimpan ke basis data valid. Active Record menyediakan berbagai jenis validasi yang dapat Anda gunakan untuk memvalidasi data Anda.

Jenis-jenis Validasi

  • acceptance
  • confirmation
  • exclusion
  • inclusion
  • length
  • numericality
  • presence
  • absence
  • uniqueness
  • format

Contoh validasi:


class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 50 }
  validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
end

Validasi Kustom

Anda dapat membuat validasi kustom dengan mendefinisikan metode validasi di model Anda:


class User < ApplicationRecord
  validate :password_complexity

  def password_complexity
    if password.present? && !password.match(/\A(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).*\z/)
      errors.add :password, "must include at least one lowercase letter, one uppercase letter, one digit, and one special character"
    end
  end
end

Menangani Kesalahan Validasi

Ketika validasi gagal, Active Record akan menambahkan pesan kesalahan ke objek errors. Anda dapat mengakses pesan kesalahan ini dalam tampilan Anda:


<% if @user.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

    <ul>
      <% @user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

7. Callback

Callback adalah metode yang dipanggil pada titik-titik tertentu dalam siklus hidup objek Active Record. Anda dapat menggunakan callback untuk melakukan tindakan seperti mengirim email, membuat log, atau memperbarui data terkait.

Jenis-jenis Callback

  • before_validation
  • after_validation
  • before_save
  • around_save
  • before_create
  • around_create
  • after_create
  • before_update
  • around_update
  • after_update
  • before_destroy
  • around_destroy
  • after_destroy
  • after_save
  • after_commit (setelah transaksi berhasil di-commit)
  • after_rollback (setelah transaksi di-rollback)

Menggunakan Callback

Contoh penggunaan callback:


class User < ApplicationRecord
  before_save :normalize_email

  private

  def normalize_email
    self.email = email.downcase.strip
  end
end

8. Scope

Scope adalah cara untuk merangkum query basis data yang umum digunakan. Scope memungkinkan Anda untuk membuat kode yang lebih ringkas dan dapat dibaca.

Mendefinisikan Scope

Anda dapat mendefinisikan scope menggunakan metode scope:


class User < ApplicationRecord
  scope :active, -> { where(active: true) }
  scope :recent, -> { order(created_at: :desc).limit(10) }
end

Menggunakan Scope

Anda dapat menggunakan scope dengan memanggilnya pada model:


active_users = User.active # Mengembalikan semua user aktif
recent_users = User.recent # Mengembalikan 10 user terbaru

9. Query Lanjutan dengan Active Record

Active Record menyediakan berbagai metode untuk melakukan query lanjutan pada basis data Anda.

Menggunakan joins

Metode joins memungkinkan Anda untuk menggabungkan tabel basis data:


users = User.joins(:posts) # Mengembalikan semua user yang memiliki post
users = User.joins("LEFT JOIN posts ON users.id = posts.user_id") # Mengembalikan semua user dan post mereka (jika ada)

Menggunakan group

Metode group memungkinkan Anda untuk mengelompokkan hasil query:


user_counts = User.group(:city).count # Mengembalikan jumlah user per kota

Menggunakan select

Metode select memungkinkan Anda untuk memilih kolom tertentu yang akan dikembalikan:


users = User.select(:id, :name) # Hanya mengembalikan kolom id dan nama

Menggunakan pluck

Metode pluck memungkinkan Anda untuk mengekstrak nilai dari satu kolom:


user_names = User.pluck(:name) # Mengembalikan array nama user

Menggunakan find_by_sql (Hati-hati!)

Metode find_by_sql memungkinkan Anda untuk menjalankan query SQL mentah. Namun, Anda harus berhati-hati saat menggunakan metode ini, karena dapat rentan terhadap serangan injeksi SQL.


users = User.find_by_sql("SELECT * FROM users WHERE name LIKE '%John%'") # Mengembalikan semua user yang namanya mengandung "John"

Sebaiknya hindari menggunakan find_by_sql jika memungkinkan dan gunakan metode Active Record yang lebih aman.

10. Serialisasi

Serialisasi adalah proses mengubah objek Ruby menjadi format yang dapat disimpan ke basis data atau dikirim melalui jaringan. Active Record menyediakan cara untuk melakukan serialisasi secara otomatis untuk kolom tertentu.

Menggunakan Serialisasi


class User < ApplicationRecord
  serialize :preferences, Hash
end

Dalam contoh ini, kolom preferences akan disimpan sebagai hash berseri. Ketika Anda membaca data dari basis data, kolom preferences akan secara otomatis di-deserialisasi menjadi hash Ruby.

11. Polimorfisme

Apa itu Asosiasi Polimorfik?

Asosiasi polimorfik memungkinkan sebuah model untuk berasosiasi dengan beberapa model lain pada satu asosiasi. Ini sangat berguna ketika Anda memiliki fitur yang dapat di-share oleh beberapa model berbeda, seperti komentar, likes, atau attachments.

Contoh Kasus

Bayangkan Anda memiliki model `Article` dan `Photo`, dan Anda ingin mengizinkan pengguna untuk memberikan komentar pada keduanya. Daripada membuat tabel `comments` terpisah untuk setiap model, Anda dapat menggunakan asosiasi polimorfik.

Implementasi di Rails

  1. Membuat Migrasi:
rails generate migration CreateComments commentable:references{polymorphic: true} body:text

Migrasi ini akan membuat tabel `comments` dengan kolom `commentable_id` dan `commentable_type`. `commentable_type` menyimpan nama model (misalnya, “Article” atau “Photo”), dan `commentable_id` menyimpan ID record terkait.

  1. Mendefinisikan Asosiasi di Model:

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end

class Article < ApplicationRecord
  has_many :comments, as: :commentable
end

class Photo < ApplicationRecord
  has_many :comments, as: :commentable
end

Sekarang Anda dapat membuat komentar untuk artikel atau foto:


article = Article.find(1)
article.comments.create(body: "Great article!")

photo = Photo.find(1)
photo.comments.create(body: "Beautiful photo!")

12. STI (Single Table Inheritance)

Konsep STI

Single Table Inheritance (STI) adalah pola desain di mana hierarki kelas disimpan dalam satu tabel basis data. Kolom “type” digunakan untuk membedakan jenis record yang berbeda.

Implementasi STI

  1. Membuat Migrasi:
rails generate model Employee type:string name:string salary:integer
  1. Mendefinisikan Model:

class Employee < ApplicationRecord
end

class Manager < Employee
end

class Programmer < Employee
end

Sekarang Anda dapat membuat manager dan programmer:


manager = Manager.create(name: "John Doe", salary: 100000)
programmer = Programmer.create(name: "Jane Doe", salary: 80000)

Kolom `type` akan secara otomatis diisi dengan “Manager” atau “Programmer”.

13. Tips dan Praktik Terbaik

Optimasi Kinerja Query

  • Gunakan Index: Pastikan Anda memiliki index yang sesuai pada kolom yang sering digunakan dalam query WHERE.
  • Batasi Kolom yang Dipilih: Hanya pilih kolom yang Anda butuhkan untuk mengurangi jumlah data yang diambil dari basis data.
  • Gunakan Eager Loading: Muat asosiasi secara eager untuk menghindari N+1 query.
  • Hindari Loop di Basis Data: Lakukan operasi massal di basis data daripada melakukan banyak query kecil dalam loop.

Menghindari N+1 Query

N+1 query adalah masalah kinerja yang umum di aplikasi Rails. Ini terjadi ketika Anda menjalankan query untuk mendapatkan data, dan kemudian menjalankan N query tambahan untuk mendapatkan data terkait.

Untuk menghindari N+1 query, gunakan eager loading (includes).

Menggunakan Index

Index adalah struktur data yang meningkatkan kecepatan operasi pencarian data pada tabel basis data. Pastikan Anda memiliki index pada kolom yang sering digunakan dalam kondisi WHERE.

14. Kesimpulan

Active Record adalah komponen penting dari Ruby on Rails yang menyederhanakan interaksi dengan basis data. Dengan memahami konsep dasar, jenis asosiasi, validasi, callback, dan tips optimasi kinerja, Anda dapat membangun aplikasi Rails yang efisien dan mudah dipelihara. Panduan ini mencakup berbagai aspek Active Record, dari konfigurasi dasar hingga teknik query lanjutan, dan diharapkan dapat membantu Anda memanfaatkan kekuatan Active Record secara maksimal dalam proyek Rails Anda.

“`

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *