---
# System prepended metadata

title: Rails Handbook

---

### Case equality operator (===)

if the right operand has an IS A relationship with the left
operand. As such, the popular name case equality operator is misleading.

This SO answer describes it thus: the best way to describe a === b is "if I have a drawer labeled a, does it make
sense to put b in it?" In other words, does the set a include the member b?
```
(1..5) === 3   => true
(1..5) === 6     => false

Integer === 42
=> true

Integer === 'fourtytwo' # => false
/ell/ === 'Hello'
/ell/ === 'Foobar'
=> true
=> false
```

--------


### 1. Lambdas:
Strict Argument Checking:
Lambdas are strict about the number of arguments you pass to them. If you pass the wrong number of arguments, they throw an ArgumentError.

```
lamb = lambda { |x, y| puts "#{x} and #{y}" }

lamb.call(1, 2)    # => "1 and 2"
lamb.call(1)       # => ArgumentError: wrong number of arguments (given 1, expected 2)

# Using stabby lambda syntax
add = ->(a, b) { a + b }
puts add.call(2, 3)  # Output: 5

# Using lambda keyword
multiply = lambda { |a, b| a * b }
puts multiply.call(2, 3)  # Output: 6

```

### 2. Procs:

Flexible Argument Checking:
Procs are more lenient with the number of arguments you pass to them. If you pass fewer arguments than expected, the missing ones are set to nil. If you pass more, the extras are ignored.
```
pr = Proc.new { |x, y| puts "#{x.inspect} and #{y.inspect}" }

pr.call(1, 2)   # => "1 and 2"
pr.call(1)      # => "1 and nil"
pr.call(1, 2, 3) # => "1 and 2"

# Defining a Proc
square = Proc.new { |x| x * x }
puts square.call(4)  # Output: 16

# Proc doesn't check the number of arguments
puts square.call  # Output: nil


```
These differences underline the importance of choosing the right tool for the job. If you want strict arity (i.e., strict number of arguments) checking, use a lambda. If you want flexibility with the number of arguments, use a proc.

-----

### 3. destroy vs delete:


#### destroy:

Calls the model's before_destroy and after_destroy callbacks and any associated callbacks.
Objects are instantiated, which can have some overhead.
Will also destroy dependent associations.
```
user = User.find(1)
user.destroy
```

#### delete:

Skips callbacks.
Directly deletes the record in the database without instantiating the object.
Doesn't trigger dependent destruction.
```
user = User.find(1)
user.delete
```

#### Block:

A chunk of code that can be passed to a method.
```
[1,2,3].each { |num| puts num }
```

### Inject Vs Reduce
inject and reduce can be used with shorthand operators for common operations like addition, multiplication, etc. This makes the code more concise.

#### Inject
```
result = [1, 2, 3, 4].inject(:+)
puts result  # Output: 10

result = [1, 2, 3, 4].inject(:*)
puts result  # Output: 24

result = [1, 2, 3, 4].inject(10, :+)
puts result  # Output: 20 (10 + 1 + 2 + 3 + 4)

```
#### Reduce
```
result = [1, 2, 3, 4].reduce(:+)
puts result  # Output: 10

result = [1, 2, 3, 4].reduce(:*)
puts result  # Output: 24

result = [1, 2, 3, 4].reduce(2, :*)
puts result  # Output: 48 (2 * 1 * 2 * 3 * 4)

```

### Optimistic vs Pessimistic Locking:

#### Optimistic Locking:
Assumes conflicts will rarely occur.
When saving, checks if the record has been updated by another transaction.
If it has, raises a conflict (e.g., ActiveRecord::StaleObjectError in Rails).

#### Pessimistic Locking:
Locks the record for the duration of the transaction.
Other transactions are blocked until the lock is released.
Can prevent data inconsistencies but can lead to deadlocks.

### Rails directory structure:

**app/**: This is the heart of any Rails application. It's where you'll find models, views, controllers, and other core components of the application's functionality.

**app/assets/**: Contains subdirectories for JavaScripts, stylesheets, and images. This is where the asset pipeline will look for assets.

**app/controllers/**: This is where your application controllers live. Controllers handle the web requests, manage logic, and hand off to the views to render data.

**app/helpers/**: Helper modules are meant to provide methods that assist with rendering views.

**app/mailers/**: This is where mailer classes live, responsible for sending emails.

**app/models/**: This is where you'll place your ActiveRecord models - classes that represent tables in the database and where you handle related business logic.

**app/views/**: Contains the templates that will be used to render the views. They're organized based on the controller they belong to.

**app/channels/**: Used for Action Cable setup for real-time features.

**app/jobs/**: Place for background jobs, which can be executed asynchronously.

**app/config/**: Contains locale files and initializers.

**bin/**: Contains Rails script files that help with various tasks (e.g., starting a server or console).

**config/**: Contains configuration files:

**config/routes.rb**: Defines the routes for your application.

**config/application.rb**: General configuration settings.

**config/environments/**: Settings specific to development, production, and test environments.

**config/initializers/**: Initialization code for various libraries and gems.

**config/database.yml**: Database configuration.

**db/**: Contains everything related to the database:

**db/migrate/**: Contains all the migration files for altering the database schema.

**db/schema.rb**: Represents the current state of the database schema.

**log/**: Contains application log files.

**public/**: Files in this directory are served directly by the web server. For example, error pages like 404.html are found here.

**test/ or spec/**: Contains tests for your application. Whether it's "test" or "spec" often depends on the testing framework you're using (e.g., Minitest vs RSpec).

**tmp/**: Temporary files (e.g., cache, session, sockets).

**vendor/**: A place for third-party code. In a typical Rails application, you might use gems instead, but sometimes you might want to vendor certain libraries.

**.gitignore**: A file used by Git to exclude certain files and directories from the repository.

**Gemfile and Gemfile.lock**: These files allow you to specify which gems (libraries) your application depends on. The Gemfile.lock is an auto-generated file that ensures all developers on a project are using the exact same gem versions.

**Rakefile**: Provides tasks that can be run from the command line using the rake command. Rails comes with many built-in rake tasks for things like database migrations.

**README.md**: A markdown file where you should describe your project, how to set it up, and other pertinent information.

### PUT VS PATCH

#### PUT:
Idempotent: Making the same PUT request multiple times will have the same effect as making it once. This implies that a PUT request is expected to provide a full representation of the resource being updated.

Definition: PUT is used to update or create a resource at a particular URI. If the resource exists, it's replaced. If it doesn't exist, it's created (if the server supports doing so).

Usage: Given that PUT is idempotent, it typically requires the client to send the entire updated representation of the resource. If you only send a partial update to a PUT endpoint, it might either result in an error or in incomplete data for the resource, depending on the API's design.
```
PUT /users/123

{
  "id": 123,
  "name": "John Doe",
  "email": "johndoe@example.com",
  "age": 30
}

```
**Even if only the age field changed, you'd typically send the entire user object to the PUT endpoint.**

#### PATCH:

Not Necessarily Idempotent: While it can be implemented in an idempotent manner, PATCH requests by nature do not guarantee idempotency. This is because PATCH is intended to provide partial updates to a resource.

Definition: PATCH is used to apply partial modifications to a resource.

Usage: Unlike PUT, which requires the entire resource data, PATCH requires only the changes. This makes PATCH more efficient when you only need to update a small part of a resource.

Example: If you're only updating the age of a user:
```
PATCH /users/123

{
  "age": 31
}

```

**Here, you only send the age attribute with its new value.**


##### Key Takeaways:
Use PUT when you're replacing a resource entirely or providing a full representation of the resource.
Use PATCH when you're making partial updates to a resource.


### Cron:
A cron is a Unix-based job scheduling program that allows users to run scripts, commands, or software at specified times and dates. The name "cron" comes from the Greek word "chronos", which means "time", and it's used to automate tasks like backups, sending emails, or any repetitive job you can think of.

#### Crontab:
crontab (short for "cron table") is the command used to view, add, remove, or modify cron jobs for a user. The crontab command interfaces with the cron daemon, managing the user's job tables.
```
*     *     *     *     *    command_to_be_executed
-     -     -     -     -
|     |     |     |     |
|     |     |     |     +----- day of the week (0 - 6) [0 is Sunday, or use names]
|     |     |     +------- month (1 - 12)
|     |     +--------- day of the month (1 - 31)
|     +----------- hour (0 - 23)
+------------- min (0 - 59)

```
The **crontab -l** command is used to list all the cron jobs for the currently logged-in user.

Let's say you want to schedule a backup script, backup.sh, to run every day at 3:30 AM.
```
30 3 * * * /path/to/backup.sh
```

If you wish to run a Python script, data_cleanup.py, every Monday at 5:45 PM:
```
45 17 * * 1 /usr/bin/python3 /path/to/data_cleanup.py
```

### Use Cases:
**Backups**: Automate database or file system backups daily, weekly, or at any desired frequency.

**Reports**: Generate and email weekly sales reports, performance metrics, etc.

**Housekeeping**: Clear out temporary files or cache directories periodically to free up space.

**Notifications**: Send out reminders, e.g., for expiring subscriptions, upcoming appointments, or system metrics.

**Updates**: Automatically update system software or databases.

**Monitoring**: Check the health status of services or websites at regular intervals and alert if they're down

### Modules:
In Ruby, a module is a collection of methods, constants, and class variables. Modules are not classes and can't create instances. They're used for namespacing and mixins (injecting functionality into classes).
```
module Greetable
  def greet
    "Hello, #{self.name}"
  end
end

class User
  include Greetable

  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

user = User.new("Alice")
puts user.greet  # Outputs: Hello, Alice
```

### Concerns:
In Rails, a concern is a specialized module that not only allows you to group related model (or controller) methods but also allows you to add class-level methods and scopes. It's Rails' way to make model or controller code more modular and organized.

```
# app/models/concerns/taggable.rb
module Taggable
  extend ActiveSupport::Concern

  included do
    has_many :tags
  end

  def tag_list
    tags.map(&:name).join(", ")
  end

  class_methods do
    def most_tagged
      # Some code to find the most tagged instance
    end
  end
end

# app/models/post.rb
class Post < ApplicationRecord
  include Taggable
end
```
### Use Cases:
**Modules**: When you want to share functionality between classes or prevent name clashes by namespacing.
**Concerns**: When your Rails models or controllers become bulky, and you want to extract and group related functionalities into separate modules. They also allow for a cleaner way to extend Active Record with both instance and class methods.

### Save an object without callbacks:

In Rails, Active Record callbacks allow you to attach code to certain lifecycle events of an object, like before it's saved, after it's created, etc. However, there might be situations where you want to save an object without triggering these callbacks.

Method: update_column and update_columns

update_column and update_columns methods allow you to update attributes of an object directly in the database, skipping validations and callbacks.

```
class User < ApplicationRecord
  before_save :set_default_username

  def set_default_username
    self.username ||= "default_username"
  end
end

user = User.find(1)
user.update_column(:username, 'new_username')
# or for multiple columns
# user.update_columns(username: 'new_username', email: 'new_email@example.com')

```

### Rake vs Rack
#### Rake:

It's a build program written in Ruby.
Used for tasks like database setup, cleanup, and general application maintenance tasks.
Rakefile in a Rails project defines tasks which can be executed.

#### Rack:
It's an interface between web servers and Ruby frameworks, including Rails.
Provides a minimal API to connect web servers that support Ruby.
A Rails application is actually a Rack application under-the-hood.

### Use Cases:
#### Rake:

Running database migrations.
Clearing temporary files.
Running custom developer-defined tasks.

#### Rack:
Middleware management.
Connecting Rails to servers like Puma, Unicorn, etc.
Building micro-frameworks or small web applications.


### Application Server vs Web Server
#### Application Server (like Puma, Unicorn):

Runs your Rails application.
Handles Ruby code execution.
Can serve multiple requests simultaneously, depending on the configuration (threaded, multi-process, etc.).
Typically slower at serving static files than a web server.

#### Web Server (like Nginx, Apache):
Can serve static files very efficiently.
Can handle SSL/TLS termination, load balancing, and more.
In a typical Rails deployment, sits in front of the application server, forwarding dynamic requests to it.

##### Use Cases:
###### Application Server:

Running the Ruby on Rails code.
Serving dynamic content.

###### Web Server:
SSL/TLS termination.
Serving static assets like images, stylesheets, and JavaScript files.
Load balancing between multiple application server instances.
Caching content for faster response times.


### has_and_belongs_to_many Table Architecture
The has_and_belongs_to_many association creates a direct many-to-many connection between models without an explicit intermediary model. To implement it, a join table is required, and by convention, the join table's name is the union of the participating model tables in alphabetical order.

Suppose we have a students and courses table, and we want to establish a many-to-many relationship between them:
```
rails generate migration CreateJoinTableStudentsCourses students courses

class CreateJoinTableStudentsCourses < ActiveRecord::Migration[6.0]
  def change
    create_join_table :students, :courses do |t|
      t.index [:student_id, :course_id]
      t.index [:course_id, :student_id]
    end
  end
end

# student.rb
class Student < ApplicationRecord
  has_and_belongs_to_many :courses
end

# course.rb
class Course < ApplicationRecord
  has_and_belongs_to_many :students
end

```
Many developers prefer to use has_many :through instead of has_and_belongs_to_many because it offers more flexibility by allowing you to work with the relationship model directly, adding validations, callbacks, or extra attributes to the join model.

### **Flatten Method logic**
```
def custom_flatten(array, result = [])
  array.each do |element|
    if element.is_a?(Array)
      custom_flatten(element, result)
    else
      result << element
    end
  end
  result
end

# Test the custom_flatten method
nested_array = [1, [2, [3, 4]], [5, 6]]
flattened_array = custom_flatten(nested_array)
puts flattened_array.inspect  # Output should be [1, 2, 3, 4, 5, 6]

```

### MetaProgramming Examples
This ability to define and alter the structure and behavior of objects and classes during execution is one of Ruby's powerful features.

#### Send() Method
send() is used to pass message to object. send() is an instance method of the Object class. 
The ﬁrst argument in
send() is the message that you're sending to the object - that is, the name of a method. 
It could be string or
symbol but symbols are preferred. Then arguments those need to pass in method, those will be the remaining
arguments in send().
```
class Hello
    def hello(*args)
        puts 'Hello ' + args.join(' ')
    end
end

h = Hello.new
h.send :hello, 'gentle', 'readers'
#=> "Hello gentle readers"

# h.send(:hello, 'gentle', 'readers') #=> Here :hello is method and rest are the arguments to method.
```
```
class Account
    attr_accessor :name, :email, :notes, :address
    def assign_values(values)
        values.each_key do |k, v|
            # How send method would look a like
            # self.name = value[k]
            self.send("#{k}=", values[k])
        end
    end
end

user_info = {
    name: 'Matt',
    email: 'test@gms.com',
    address: '132 random st.',
    notes: "annoying customer"
}

account = Account.new
If attributes gets increase then we would messup the code

#--------- Bad way --------------
account.name = user_info[:name]
account.address = user_info[:address]
account.email = user_info[:email]
account.notes = user_info[:notes]

# --------- Meta Programing way --------------
account.assign_values(user_info) # With single line we can assign n number of attributes

puts account.inspect

Note: send() itself is not recommended anymore. Use __send__() which has the power to call private methods, or
(recommended) public_send()
```

#### Dynamic Filters:
Using metaprogramming to dynamically create methods for filtering photos based on attributes.
```
class Album
  FILTERS = [:by_date, :by_location, :by_tag]

  FILTERS.each do |filter|
    define_method("photos_#{filter}") do |value|
      # Logic to filter photos by the given criteria
      puts "Filtering photos #{filter} with value #{value}"
    end
  end
end

album = Album.new
album.photos_by_date("2023-08-25")
=> Filtering photos by_date with value 2023-08-25
album.photos_by_location("Paris")
=> Filtering photos by_location with value Paris

```
#### Dynamic Event Hooks:
Creating hooks for certain events in the lifecycle of a photo (e.g., when a photo is viewed, liked, shared).

```
class Photo
  EVENTS = [:viewed, :liked, :shared]

  EVENTS.each do |event|
    define_method("on_#{event}") do
      # Logic to handle the event
      puts "Photo has been #{event}"
    end
  end
end

photo = Photo.new
photo.on_viewed
photo.on_shared

```
#### Dynamic Tagging System:
Allow users to add custom tags to photos and then retrieve photos by those tags.
```
class Photo
  def add_tag(tag)
    # Logic to add a tag to a photo
    self.tags << tag

    # Dynamically create a method to check for this specific tag
    self.class.define_method("with_#{tag}") do
      # Logic to fetch photos with this specific tag
      puts "Fetching photos with tag: #{tag}"
    end
  end
end

photo = Photo.new
photo.add_tag("vacation")
Photo.with_vacation # Fetching photos with tag: vacation

```

Imagine you want to categorize your photos into different genres, like 'Portraits', 'Landscapes', 'Wildlife', etc.

With metaprogramming, we can dynamically generate methods to categorize and retrieve photos based on these categories:

1. Define a Photo class:
```
class Photo
  attr_accessor :title, :category

  @@photos = []

  def initialize(title, category = nil)
    @title = title
    @category = category
    @@photos << self
  end

  def self.all
    @@photos
  end

  def self.categorize(name)
    # Dynamically generate method to get photos of this category
    define_singleton_method("in_#{name.downcase}") do
      @@photos.select { |photo| photo.category == name }
    end
  end

  def self.categories(*names)
    names.each { |name| categorize(name) }
  end
end

```
Define categories using the categories method:

```
Photo.categories('Portraits', 'Landscapes', 'Wildlife')
```

```
Create and categorize photos:
 
photo1 = Photo.new("Portrait of John", "Portraits")
photo2 = Photo.new("Sunset at Beach", "Landscapes")
photo3 = Photo.new("Eagle in the Sky", "Wildlife")
photo4 = Photo.new("Mountain Range", "Landscapes")

Use the dynamically generated methods to retrieve photos by category:

puts Photo.in_portraits.map(&:title)  # ["Portrait of John"]
puts Photo.in_landscapes.map(&:title) # ["Sunset at Beach", "Mountain Range"]
puts Photo.in_wildlife.map(&:title)   # ["Eagle in the Sky"]

```

1. We've created a simple Photo class to represent photos with titles and categories.
2. The categorize method dynamically generates methods to filter photos by category.
3. The categories method is a utility to define multiple categories at once. Each category passed to this method will create a new method to retrieve photos in that category.
4. We then create and categorize photos.
5. Lastly, we use the dynamically generated methods to retrieve photos by their category.

### INNER JOIN
An INNER JOIN returns only the rows that have matching values in both tables.

![](https://hackmd.io/_uploads/H1GPBniT3.png)
```
SELECT Students.name, Scores.score
FROM Students
INNER JOIN Scores ON Students.id = Scores.student_id;

```
![](https://hackmd.io/_uploads/S1yiB3iph.png)

LEFT OUTER JOIN
A LEFT OUTER JOIN returns all the rows from the left table, and the matching rows from the right table. If there's no match, NULL values are returned for columns from the right table.

```
SELECT Students.name, Scores.score
FROM Students
LEFT OUTER JOIN Scores ON Students.id = Scores.student_id;
```
![](https://hackmd.io/_uploads/Skjsr2i6h.png)

### Polymorphic associations

```
rails generate model Post title:string
rails generate model Video title:string
rails generate model Comment body:text commentable:references{polymorphic}
```

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


create_table :comments do |t|
  t.text :body
  t.integer :commentable_id
  t.string :commentable_type
  t.timestamps
end

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

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

# Creating a comment for a post
post = Post.create(title: "Hello World")
comment1 = Comment.create(body: "A comment on a post.", commentable: post)

# Creating a comment for a video
video = Video.create(title: "My Video")
comment2 = Comment.create(body: "A comment on a video.", commentable: video)

# Fetch comments of a post
post_comments = post.comments

# Fetch comments of a video
video_comments = video.comments

# Find the parent model (Post or Video) for a comment
parent_for_comment1 = comment1.commentable # This will return the related Post object
parent_for_comment2 = comment2.commentable # This will return the related Video object

```

#### Benefits of Polymorphic Associations:

DRY code: Without polymorphic associations, you would end up with separate associations and tables for each PostComment, VideoComment, etc. Polymorphic associations eliminate that redundancy.

Flexibility: You can easily add more models that can be commented on without having to change the Comment model or table.

Query Efficiency: It allows you to retrieve the comments for multiple types of commentable objects in one query, making it easier to manage and optimize queries.

### Single Table Inheritance (STI) 

It is a feature in Ruby on Rails that allows a single database table to be used to represent multiple classes in an inheritance hierarchy. This is useful when you have models that share common attributes and behavior but also have their own specific attributes and behavior.

##### Rails utilizes a type column in the database table to keep track of the class for a given row. 

```
rails generate migration CreateVehicles make:string model:string type:string payload_capacity:integer

# app/models/vehicle.rb

class Vehicle < ApplicationRecord
  # common behavior for all vehicles
end

# app/models/car.rb

class Car < Vehicle
  # behavior specific to cars
end

# app/models/truck.rb

class Truck < Vehicle
  # behavior specific to trucks
end

Car.create(make: 'Toyota', model: 'Camry')
Truck.create(make: 'Ford', model: 'F-150', payload_capacity: 5000)

vehicles = Vehicle.all
# This will give you an array of Vehicle, Car, and Truck instances based on the `type` column

cars = Car.all
# This will only give you the rows where `type` is 'Car'

trucks = Truck.all
# This will only give you the rows where `type` is 'Truck'

class User < ActiveRecord::Base
    self.inheritance_column = :entity_type # can be string as well
end
class Admin < User; end

```

By default STI model class name is stored in a column named type. But its name can be changed by overriding
inheritance_column value in a base class.

#### Advantages and Disadvantages
##### Advantages:
1. DRY: Code is not duplicated across multiple tables.
2. Easy Queries: It's easy to fetch all records of a certain type or parent type.
3. Intuitive Modeling: A natural fit for certain kinds of domain models.
##### Disadvantages:
1. Complex Queries: As more subclasses are added, it can become increasingly complex to query for specific attributes.
2. Table Bloat: The single table will contain columns for all attributes of all classes in the hierarchy, which may lead to many NULL values.
3. Type Coupling: Because the type field is string-based, renaming classes can lead to issues unless handled carefully.


Having type column in a Rails model without invoking STI can be achieved by assigning `:_type_disabled` to
inheritance_column:

```
class User < ActiveRecord::Base
    self.inheritance_column = :_type_disabled
end
```

### Monkey Patching

Monkey Patching is a way of modifying and extending classes in Ruby. Basically, you can modify already deﬁned classes in Ruby, adding new methods and even modifying previously deﬁned methods.

#### Changing an existing ruby method
```
puts "Hello readers".reverse # => "sredaer olleH"
class String
    def reverse
        "Hell riders"
    end
end
puts "Hello readers".reverse # => "Hell riders"
```

### Mixin

In Ruby, a mixin is a way to share code among multiple classes. This is done through modules, which can contain methods that get mixed into classes using the include or extend keywords. Mixins are a form of composition and offer an alternative to inheritance for code reuse.

Instance Method Mixin

Let's consider a simple example where we have a Document and a Person class, both of which need to output a summary.

```
module Summarizable
  def summary
    "#{self.class.name} Summary: #{self.to_s}"
  end
end

class Document
  attr_accessor :text
  
  include Summarizable
  
  def initialize(text)
    @text = text
  end
  
  def to_s
    @text
  end
end

class Person
  attr_accessor :name, :age
  
  include Summarizable
  
  def initialize(name, age)
    @name = name
    @age = age
  end
  
  def to_s
    "#{@name}, #{@age} years old"
  end
end

doc = Document.new("This is a sample document.")
puts doc.summary
# Output: "Document Summary: This is a sample document."

person = Person.new("Alice", 30)
puts person.summary
# Output: "Person Summary: Alice, 30 years old"

```

```
module Foo
    def foo_method
        puts 'foo_method called!'
    end
end

module Bar
    def bar_method
        puts 'bar_method called!'
    end
end

class Baz
    include Foo
    include Bar
    def baz_method
        puts 'baz_method called!'
    end
end

new_baz = Baz.new
new_baz.baz_method #=> 'baz_method called!'
new_baz.bar_method #=> 'bar_method called!'
new_baz.foo_method #=> 'foo_method called!'
```

```
module SomeMixin
    def foo
        puts "foo!"
    end
end

class Bar
    extend SomeMixin
    def baz
        puts "baz!"
    end
end

b = Bar.new
b.baz
# => "baz!"
b.foo
# NoMethodError, as the method was NOT added to the instance
Bar.foo
# => "foo!"
# works only on the class itself
```

### Self-Referential Association
Self-referential association is used to associate a model with itself. The most frequent example would be, to manage association between a friend and his follower.

```
rails g model friendship user_id:references friend_id:integer

# db/migrate/xxxxxx_create_friendships.rb

class CreateFriendships < ActiveRecord::Migration[6.0]
  def change
    create_table :friendships do |t|
      t.references :user, null: false, foreign_key: true
      t.references :friend, null: false, foreign_key: { to_table: :users }

      t.timestamps
    end

    add_index :friendships, [:user_id, :friend_id], unique: true
  end
end

now you can associate models like;
class User < ActiveRecord::Base
    has_many :friendships
    has_many :friends, :through => :friendships
    has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
    has_many :inverse_friends, :through => :inverse_friendships, :source => :user
end

and the other model will look like;
class Friendship < ActiveRecord::Base
    belongs_to :user
    belongs_to :friend, :class_name => "User"
end

# Create users
user1 = User.create(name: 'Alice')
user2 = User.create(name: 'Bob')

# Create friendship
user1.friendships.create(friend: user2)

# List friends
user1.friends # => [user2]
user2.inverse_friends # => [user1]

```


#### The has_many :through association
```
class Physician < ApplicationRecord
    has_many :appointments
    has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
    belongs_to :physician
    belongs_to :patient
end
class Patient < ApplicationRecord
    has_many :appointments
    has_many :physicians, through: :appointments
end
```
#### The has_one :through association

A has_one :through association sets up a one-to-one connection with another model. This association indicates
that the declaring model can be matched with one instance of another model by proceeding through a third model.
```
class Supplier < ApplicationRecord
    has_one :account
    has_one :account_history, through: :account
end

class Account < ApplicationRecord
    belongs_to :supplier
    has_one :account_history
end

class AccountHistory < ApplicationRecord
    belongs_to :account
end
```


#### Skipping Validations

decrement!
decrement_counter
increment!
increment_counter
toggle!
touch
update_all
update_attribute
update_column
update_columns
update_counters

#### User.save(validate: false)

### Scopes
Scopes act as predeﬁned ﬁlters on ActiveRecord models.
A scope is deﬁned using the scope class method.
```
class Person < ActiveRecord::Base
    #attribute :first_name, :string
    #attribute :last_name, :string
    #attribute :age, :integer
    
    # define a scope to get all people under 17
    scope :minors, -> { where(age: 0..17) }
    
    # define a scope to search a person by last name
    scope :with_last_name, ->(name) { where(last_name: name) }
end
```
Scopes can be called directly oﬀ the model class:
```
minors = Person.minors
```
Scopes can be chained:
`peters_children = Person.minors.with_last_name('Peters')`

User.first
```
SELECT
`users`.* FROM `users`
ORDER BY `users`.`id` ASC LIMIT 1
```

#### Includes
ActiveRecord with includes ensures that all of the speciﬁed associations are loaded using the minimum possible
number of queries. So when querying a table for data with an associated table, both tables are loaded into
memory.

```
@authors = Author.includes(:books).where(books: { bestseller: true } )

# this will print results without additional db hitting
@authors.each do |author|
    author.books.each do |book|
        puts book.title
    end
end
```
Author.joins(:books).where(books: { bestseller: true } ) will load only authors with conditions into
memory without loading books. Use joins when additional information about nested associations isn't required.

```
@authors = Author.joins(:books).where(books: { bestseller: true } )
# this will print results without additional queries
@authors.each { |author| puts author.name }

# this will print results with additional db queries
@authors.each do |author|
    author.books.each do |book|
        puts book.title
    end
end
```

#### Joins

User.joins(:posts)
will produce the following SQL query:
`"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id""`

```
User.joins(:posts).where(posts: { title: "Hello world" })
```

Nested joins:
```
User.joins(posts: :images).where(images: { caption: 'First post' })

"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" INNER JOIN
"images" ON "images"."post_id" = "images"."id""
```

##### Mind that find_by doesn't throw any exception by default. If the result is an empty set, it returns nil instead of find.

##### delete_all method. to be called directly on a model, to delete all records in that table, or a collection. Beware though, as .delete_all does not instantiate any object hence does not provide any callback (before_* and after_destroy don't get triggered).


#### case insensitive search

```
addresses = Address.arel_table
Address.where(addresses[:address].matches("%street%"))
```

### Docker
Docker is a platform for building, shipping, and running applications in containers. A container is a lightweight, standalone, and executable package of software that includes everything needed to run an application, including code, runtime, libraries, system tools, and settings. Docker makes it easy to package an application and all its dependencies into a single container, which can then be deployed to any environment that supports Docker.

```
# Use an official Ruby runtime as a parent image
FROM ruby:3.0.3

# Set the working directory
WORKDIR /app

# Install dependencies
RUN apt-get update && \
    apt-get install -y \
    build-essential \
    nodejs \
    postgresql-client && \
    rm -rf /var/lib/apt/lists/*

# Install gems
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && \
    bundle install --jobs 4

# Copy the application code
COPY . .

# Expose ports
EXPOSE 3000

# Set the entrypoint command
CMD ["rails", "server", "-b", "0.0.0.0"]
```

```
version: "3"
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    depends_on:
      - db
      - redis
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp_development
  redis:
    image: redis:6.0
```

##### docker-compose up --build

```
version: "3"
services:
  web:
    image: your-dockerhub-username/myapp:latest
    environment:
      RAILS_ENV: production
      DATABASE_URL: "postgres://postgres:password@db/myapp_production"
      REDIS_URL: "redis://redis:6379/0"
    ports:
      - "80:3000"
    depends_on:
      - db
      - redis
    restart: always
  db:
    image: postgres:12
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp_production
    volumes:
      - db_data:/var/lib/postgresql/data
    restart: always
  redis:
    image: redis:6.0
    restart: always
volumes:
  db_data:
```

#### Nginx Configuration
```
upstream myapp {
  server localhost:3000;
}

server {
  listen 80;
  server_name example.com;

  location / {
    proxy_pass http://myapp;
    proxy_set_header Host $host
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}
```

#### Github CI/CD
```
# This is a basic workflow to help you get started with Actions

name: CD

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the production branch
  push:
    branches: [ uat ]
 # pull_request:
 #   branches: [ main ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  deploy:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: appleboy/ssh-action@master
        with:
          host: ${{secrets.UAT_SSH_HOST}}
          key: ${{secrets.UAT_SSH_KEY}} #private key
          username: ${{secrets.UAT_SSH_USERNAME}}
          script: |
            cd /var/www/html/app
            docker-compose stop
            git pull
            docker-compose up -d
            ls -al
```
#### N+1 Query

One of the frequent performance antipatterns in ORMs is the N+1 query problem. It occurs when an application retrieves data from the database and then loops through the results of that data, or when a query is run on each result of the prior query.

```
# app/models/Company.rb
class Company < ApplicationRecord
  belongs_to :user
end

# app/models/user.rb
class User < ApplicationRecord
  has_many :companies
end

Company.all.each do |Company|
  puts "#{Company.title} was written by #{Company.user.username}"
end

The above code works, but it makes far too many independent database queries:

Company Load (0.5ms)  SELECT "companies".* FROM "companies"
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 5], ["LIMIT", 1]]
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 6], ["LIMIT", 1]]
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 9], ["LIMIT", 1]]
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 10], ["LIMIT", 1]]
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
```
That is 7 separate database queries

In contrast to lazy loading, eager loading occurs when a query loads a resource as soon as the code is executed. As part of the query, it also loads related entities.
We need to reduce the number of independent database queries in order to improve the performance of the previous example.

```
Company.includes(:user).each do |Company|
  puts "#{Company.title} was written by #{Company.user.username}"
end

Company Load (103.7ms)  SELECT "companies".* FROM "companies"
  User Load (32.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (?, ?, ?, ?, ?)  [["id", 1], ["id", 5], ["id", 6], ["id", 9], ["id", 10], ["id", 15]]
```

### RubyGems

RubyGems is a package manager for the Ruby programming language. It provides a standard format for distributing Ruby libraries (known as "gems") and a way to easily install, manage and update these gems in a Ruby application.

A gem is a self-contained package of code, assets, and documentation that can be used in a Ruby application. Gems typically provide additional functionality that is not part of the core Ruby language, such as libraries for connecting to databases, handling HTTP requests, and so on.

RubyGems makes it easy to find, install, and manage gems in a Ruby application. You simply specify the gems that your application depends on in a file called the Gemfile, and then use the bundle install command to download and install all the gems specified in the file. The bundle install command also resolves any dependencies between gems and ensures that the correct version of each gem is installed.

##### Generate the gem skeleton
1. Open your terminal and navigate to the directory where you want to create your gem
2. Run the following command to create the gem skeleton: $ bundle gem my_accounting_app
3. This will create a directory named my_accounting_app with the basic structure of a Ruby gem.

```
module MyAccountingApp
  def self.total_amount(amount, tax)
    amount + (amount * tax)
  end
end
```

In the root directory of your gem, you'll find a file named my_accounting_app.gemspec. This is where you'll specify the metadata for your gem, such as its name, version, author, and description.

```
# my_accounting_app.gemspec
Gem::Specification.new do |spec|
  spec.name        = "my_accounting_app"
  spec.version     = "0.1.0"
  spec.authors     = ["Your Name"]
  spec.email       = ["your_email@example.com"]
  spec.summary     = "A gem for accounting applications"
  spec.description = "A gem that provides methods for accounting applications"
  spec.files       = Dir["lib/**/*.rb"]
  spec.require_paths = ["lib"]
end
```

##### Build the gem

```
gem build my_accounting_app.gemspec

Create a new Rails application: $ rails new my_rails_app
Add the following line to the Gemfile of your Rails application:

gem "my_accounting_app", path: "/path/to/my_accounting_app"
```

```
class InvoicesController < ApplicationController
  def show
    amount = params[:amount].to_f
    tax = params[:tax].to_f
    @total_amount = MyAccountingApp.total_amount(amount, tax)
  end
end

Rails.application.routes.draw do
  get "/invoices/show", to: "invoices#show"
end
```

Run the following command to publish your gem: 
`gem push my_accounting_app-0.1.0.gem`


### Page caching
You can use the ActionPack page_caching gem to cache individual pages

This stores the result of one dynamic
request as a static HTML ﬁle, which is served in place of the dynamic request on subsequent requests

```
class UsersController < ActionController::Base
    caches_page :index
end

Use expire_page to force expiration of the cache by deleting the stored HTML ﬁle:
class UsersController < ActionController::Base
    caches_page :index
    def index
        @users = User.all
    end
    def create
        expire_page :action => :index
    end
end
The syntax of expire_page mimics that of url_for and friends.
```

### Fragment caching

Use cache.write to write a value to the cache:
```
Rails.cache.write('city', 'Duckburgh')
Rails.cache.read('city')
=> 'Duckburgh'
```

```
Rails.cache.fetch('user') do
    User.where(:is_awesome => true)
end
```

#### Nested Forms
```
<%= nested_form_for @project do |f| %>
    <%= f.label :name %>
    <%= f.text_field :name %>
    <% # Now comes the part for `Todo` object %>
    <%= f.fields_for :todo do |todo_field| %>
        <%= todo_field.label :name %>
        <%= todo_field.text_field :name %>
    <% end %>
<% end %>
```

#### CSV Parsing

```
class Product< ApplicationRecord
    def self.import(file)
        CSV.foreach(file.path, headers: true) do |row|
            Product.create! row.to_hash
        end
    end
end
```

#### Rails Best Practices

##### Fat Model, Skinny Controller
“Fat Model, Skinny Controller” refers to how the M and C parts of MVC ideally work together. Namely, any non-
response-related logic should go in the model, ideally in a nice, testable method. Meanwhile, the “skinny” controller
is simply a nice interface between the view and model.

```
Let’s look at a simple example. Say you have code like this:
def index
    @published_posts = Post.where('published_at <= ?', Time.now)
    @unpublished_posts = Post.where('published_at IS NULL OR published_at > ?', Time.now)
end

You can change it to this:
def index
    @published_posts = Post.published
    @unpublished_posts = Post.unpublished
end

Then, you can move the logic to your post model, where it might look like this:

scope :published, ->(timestamp = Time.now) { where('published_at <= ?', timestamp) }
scope :unpublished, ->(timestamp = Time.now) { where('published_at IS NULL OR published_at > ?',
timestamp) }
```

#### Split routes into multiple ﬁles

```
config/routes.rb:
YourAppName::Application.routes.draw do
    require_relative 'routes/admin_routes'
    require_relative 'routes/sidekiq_routes'
    require_relative 'routes/api_routes'
    require_relative 'routes/your_app_routes'
end

config/routes/api_routes.rb:
YourAppName::Application.routes.draw do
    namespace :api do
    # ...
    end
end
```

#### Collection Vs Member Routes
A member route will require an ID because it acts on a member of the resource. This means that it's used for actions that are performed on a specific instance of the resource. For example, 
##### if you have a Users resource and you want to add a custom action that changes the status of a specific user, you could define a member route like this:
```
resources :users do
  member do
    get 'change_status'
  end
end

/users/1/change_status
```
A collection route doesn't require an ID because it acts on a collection of the resource. This means that it's used for actions that are performed on the resource as a whole and not on individual instances. For example,
##### if you want to add a custom action that displays all users who are online, you could define a collection route like this:
```
resources :users do
  collection do
    get 'online'
  end
end

/users/online
```

10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 55

```
def add(n)
  if n == 1
    return n
  end
  n + add(n - 1)
end
```

### Database View

A database view is a virtual table based on the result-set of an SQL statement. It does not store the data itself but provides a way to represent the result of complex queries in a simplified manner. You can treat views like regular database tables in your queries.

Example
Let's say you have two tables: orders and products. You want to create a view that shows the total sales for each product.
```
rails generate migration CreateTotalSalesPerProductView

# app/models/total_sales_per_product.rb
class TotalSalesPerProduct < ApplicationRecord
  self.table_name = 'total_sales_per_product'
  self.primary_key = 'id' # Assuming the view has an 'id' field
end


class CreateTotalSalesPerProductView < ActiveRecord::Migration[6.0]
  def up
    execute <<-SQL
      CREATE VIEW total_sales_per_product AS
      SELECT products.id AS product_id, products.name AS product_name, SUM(orders.amount) AS total_sales
      FROM products
      INNER JOIN orders ON products.id = orders.product_id
      GROUP BY products.id;
    SQL
  end

  def down
    execute <<-SQL
      DROP VIEW IF EXISTS total_sales_per_product;
    SQL
  end
end

```

### Database Indexing in Rails

Database indexing is a performance optimization technique that speeds up data retrieval operations. An index is a data structure that improves the speed of data retrieval operations on a database table at the cost of additional storage and decreased performance on data modification operations.

```
class AddIndexToUsersEmail < ActiveRecord::Migration[6.0]
  def change
    add_index :users, :email, unique: true
  end
end

```

1. Database Views: Useful for simplifying complex queries and calculations. They act like virtual tables.
2. Database Indexing: Useful for speeding up data retrieval operations. They create a data structure that allows for quicker lookups.

### Class Vs Module

A class is a blueprint for creating objects and encapsulates methods that operate on an object's attributes. Classes support inheritance, allowing you to create a new class that is a subclass of an existing class.

##### Module
A module is a collection of methods and constants that can be mixed into a class using include or extend. Modules cannot be instantiated, and they don't support inheritance. However, they are excellent for reusability and keeping classes clean and organized.

```
# app/models/concerns/authentication.rb
module Authentication
  def authenticate(password)
    # Logic for authentication
  end
end

# app/models/user.rb
class User < ApplicationRecord
  include Authentication

  def full_name
    "#{first_name} #{last_name}"
  end
end

user = User.new
user.authenticate("some_password")
```

```
╔═══════════════╦═══════════════════════════╦═════════════════════════════════╗
║               ║ class                     ║ module                          ║
╠═══════════════╬═══════════════════════════╬═════════════════════════════════╣
║ instantiation ║ can be instantiated       ║ can *not* be instantiated       ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ usage         ║ object creation           ║ mixin facility. provide         ║
║               ║                           ║   a namespace.                  ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ superclass    ║ module                    ║ object                          ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ methods       ║ class methods and         ║ module methods and              ║
║               ║   instance methods        ║   instance methods              ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ inheritance   ║ inherits behaviour and can║ No inheritance                  ║
║               ║   be base for inheritance ║                                 ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ inclusion     ║ cannot be included        ║ can be included in classes and  ║
║               ║                           ║   modules by using the include  ║
║               ║                           ║   command (includes all         ║
║               ║                           ║   instance methods as instance  ║
║               ║                           ║   methods in a class/module)    ║
╟───────────────╫───────────────────────────╫─────────────────────────────────╢
║ extension     ║ can not extend with       ║ module can extend instance by   ║
║               ║   extend command          ║   using extend command (extends ║
║               ║   (only with inheritance) ║   given instance with singleton ║
║               ║                           ║   methods from module)          ║
╚═══════════════╩═══════════════════════════╩═════════════════════════════════╝
```

#### String
A string is a mutable object that can be changed after it has been created. Each string you create is a separate object, even if the text content is the same.
```
# Creating a string
name = String.new("John")

# Modifying a string
name << " Doe"

# Comparing two strings with the same content
puts "John" == "John"  # Output: true

# Two different string objects with the same content
puts "John".object_id == "John".object_id  # Output: false
```

#### Symbol
A symbol is an immutable object, meaning it cannot be changed once it has been created. All symbols with the same content refer to the same object, making them more memory-efficient for certain operations like hash keys.
```
# Creating a symbol
name = :John

# Symbols are immutable
# name << " Doe"  # This will raise an error

# Comparing two symbols with the same content
puts :John == :John  # Output: true

# Same object ID for the same content
puts :John.object_id == :John.object_id  # Output: true
```

### Include
The include method is used to mix in a module's methods as instance methods in the target class. This allows you to share behavior across multiple classes.
```
module Greetable
  def greet
    "Hello, I am #{self.class.name}"
  end
end

class Person
  include Greetable
end

p = Person.new
puts p.greet  # Output: "Hello, I am Person"
```

### Extend
The extend method is used to add a module's methods as class methods to the target class or object.

```
module ClassMethods
  def categories
    ["Food", "Drink"]
  end
end

class Product
  extend ClassMethods
end

puts Product.categories  # Output: ["Food", "Drink"]
```
### Prepend
The prepend method is used to insert a module's methods into the ancestors chain before the methods of the class itself. This allows you to override methods and call super to get the original functionality.
```
module Greetable
  def greet
    "Hello, I am #{self.class.name}"
  end
end

module OverrideGreet
  def greet
    "Hi, " + super
  end
end

class Person
  include Greetable
  prepend OverrideGreet
end

p = Person.new
puts p.greet  # Output: "Hi, Hello, I am Person"
```

### Require
The require method is used to load a Ruby file and execute all its statements. Once a file has been required, it won't be loaded again if require is called with the same path.
```
# In lib/my_module.rb
module MyModule
  def hello
    "Hello"
  end
end

# In another file
require 'lib/my_module'

class MyClass
  include MyModule
end

puts MyClass.new.hello  # Output: "Hello"
```

### Load
The load method is similar to require, but it re-executes the file every time it is called, which can be useful for reloading code without restarting the application.
```
# In lib/my_module.rb
module MyModule
  def hello
    "Hello"
  end
end

# In another file
load 'lib/my_module.rb'

class MyClass
  include MyModule
end

puts MyClass.new.hello  # Output: "Hello"
```

#### Summary
**include**: Adds instance methods from a module to a class.
**extend**: Adds class methods from a module to a class or object.
**prepend**: Inserts a module's methods before the class's own methods, allowing for overrides.
**require**: Loads and executes a Ruby file once.
**load**: Loads and executes a Ruby file every time it's called.


### Scope Variables
#### Local Variable
Local variables are the most straightforward type of variable. They are available only within the method, loop, or block where they are defined.
```
def show
  message = "Hello, World!"  # Local variable
  puts message
end
```

#### Instance Variables
Instance variables are available throughout the current instance of the class. They are prefixed with an @ symbol.
```
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])  # Instance variable
  end
end
```

#### Class Variables
Class variables are shared among a class and all its descendants. They are prefixed with @@.
```
class Product
  @@count = 0  # Class variable

  def initialize
    @@count += 1
  end

  def self.count
    @@count
  end
end
```

#### Global Variables
Global variables are accessible throughout your entire application. They are prefixed with a $ symbol. However, their use is generally discouraged in favor of other variable types or constants.
```
$global_variable = "I'm available everywhere"  # Global variable
```

#### Constants
Constants in Ruby are used to store values that should not be changed once they are assigned. They are written in all uppercase.
```
# app/models/article.rb
class Article < ApplicationRecord
  STATUS = ['Draft', 'Published'].freeze  # Constant
end
```

#### Summary
1. Local Variables: Limited to the method, loop, or block where they are defined.
2. Instance Variables: Available throughout the current instance of the class.
3. Class Variables: Shared among a class and all its descendants.
4. Global Variables: Accessible throughout the entire application.
5. Constants: Immutable variables, usually used for storing settings or other unchanging values.

### Visiblity Scopes
1. Public
By default, all methods are public except for initialize, which is always private. Public methods can be called by any object that can access the class or instance.
```
class MyClass
  def public_method
    "I'm public!"
  end
end

obj = MyClass.new
puts obj.public_method  # Output: "I'm public!"
```

2. Protected
Protected methods can be called only within the same class or its subclasses, and they can also be called by other instances of the same class.
```
class MyClass
  protected

  def protected_method
    "I'm protected!"
  end
end

class MyDerivedClass < MyClass
  def call_protected_method_on(obj)
    puts obj.protected_method
  end
end

obj1 = MyDerivedClass.new
obj2 = MyDerivedClass.new
obj1.call_protected_method_on(obj2)  # Output: "I'm protected!"
```

3. Private
Private methods can only be called within the context of the current object (self). They cannot be accessed by other instances of the same class.
```
class MyClass
  private

  def private_method
    "I'm private!"
  end

  public

  def call_private_method
    puts private_method
  end
end

obj = MyClass.new
obj.call_private_method  # Output: "I'm private!"
```

### Design Patterns 
1. Service Objects
2. View Objects (Presenter)
3. Query Objects
4. Decorators
5. Form Objects
6. Value Objects
7. Policy Objects
8. Builder
9. Interactor
10. Observer

#### Service Objects
A Service Object is PORO – Plain Old Ruby Object, which is meant to encapsulate business logic and complex calculations into manageable classes and methods.

When we need to perform complex calculations or business logic, e.g., if we need to calculate employees’ salaries based on their attendance.

When we need to implement any other API, we need to implement a payment gateway such as Stripe.

When we want to import CSV that contains the bulk of data. 4. When we need to clear garbage/unused/old data from the database efficiently, it won’t affect the existing data.
```
class PaymentsController < ApplicationController 
def create
    PaymentService.new(params).call 
        redirect_to payments_path 
    rescue Stripe: : CardError => e 
        flash[:error] = e.message
        redirect_to new_Payment_path 
    end 
end
```
```
class Payment Service 
    def initialize(options = {}) 
      options.each pair do Jkey, value
        instance_variable_set("@#{key}", value) 
      end 
    end
    
    def call
      Stripe: : Charge.create(charge_attributes),
   end

   private

   attr_reader : email, :source, :amount, :description

   def amount
     @amount. to_i * 100 
   end

   def customer
     @customer ||= Stripe::Customer.create(customer_attributes),
   
   def customer_attributes
   {
    email: email, 
    source: source
    }  
   end

    def charge_attributes
    {
     customer: customer.id, 
     amount: amount, 
     description: description
    }
    end
end
```

#### View Objects (Presenter)
View Objects allow us to encapsulate all view-related logic and keep both models and views neat. View objects are the kind of rails patterns that are easy to test as they are just classes.

To solve the calculation logic problem, we can use rails helper, but if the complexity of the code is high, in that case, we should use the Presenter.

```
<p> 
  User Full Name: <%= "#{user.first_name} #{user. last_name}" %>       
  <%= link_to "View More Detail", user, class: "W-75 p-3      text-#{user.active? ? "orange" : "
green"} border-#{user.active? ? "orange" : "green"}" %>
</p>
```
**Solution**
```
app/presenters/user_presenter.rb 

class UserPresenter 
  def initialize(user)
    @user = user
  end

   def full_name
     "#{@user.first_name} #{@user. last_name}", 
   end

   def css_color
    @user.active?? "orange" : "green", 
   end
end

<% presenter = UserPresenter.new(user) %> 
User Full Name: <%= presenter.full_name %> 
<%= link_to "View More Detail", user, class: "W-75 p-3   text-#{presenter.css_color} border-#{presenter.css_color}" %> 

```

#### Query Object
Query Object is a design pattern in rails that lets us fetch query logic from Controllers and Models into reusable classes.
```
class PostsController < ApplicationController 
    def index 
      @posts = Post.accessible_by(current_ability)
                   .where(type: :video)
                   .where('view_count > ?', 100), 
    end
end
```

Solution
To make the controller skinny, readable, and neat, we can use scopes:
```
class Post < ActiveRecord::Base,
   scope : video_type, ->{ where(type: :video) } 
   scope : popular, -> { where('view_count > ?', 1000) }
   scope : popular_video_type, -> { popular.video_type } 
end
```

```
class Articles Controller < ApplicationController 
   def index 
     @posts = Post.accessible_by(current_ability),
                  .popular_video_type 
     end 
end
```
```
class VideoQuery 
   def call(ability) 
      ability
        .where(type: : video) 
        .where('view_count > ?', 1000)
   end
end

class PostsController < ApplicationController 
   def index
      ability = Post.accessible_by(current_ability),
      @articles = VideoQuery.new.call(ability) 
   end 
end
```

#### Decorators
The decorator is a design pattern that allows the behavior to be added to an object, dynamically, without disturbing the behavior of other objects of the same class. Decorators can be useful for cleaning up logic/code written inside the view and controller in an RoR application.

Create an app/decorator folder.
Add decorate helper in ApplicationHelper.

```
module ApplicationHelper 
  def decorate(model_name, decorator_class = nil),
    (decorator_class || "#{model_name.      class}Decorator".constantize).new(model_name), 
     end 
end
```

Add base_decorator.rb in app/decorators folder.
```
class BaseDecorator < SimpleDelegaton 
    def decorate (model_name, decorator_class = nil),
        ApplicationController.helpers.decorate(model_name, decorator_class), 
    end 
end
```
Add user_decorator.rb in app/decorators folder.
```
class UserDecorator < BaseDecorator
  def full name 
    "#{fname} #{lname}"
  end 
end
```
Initialize @user_decorator in your user_controller.
```
class users Controller < Application Controller 
  def show
     @user_decorator = helpers. decorate(current_user), 
  end
end

<%= @user_decorator.full_name %> 
<%= @user_decorator.email %>
```

#### Form Objects
The form object is a design pattern that is used to encapsulate the code related to validation and persisting data into a single unit. Let’s have a look at the example of the Form Objects.

Let’s assume that we have a rails post model and a controller (posts_controller) action for creating the new post. Let’s discuss the problem, Here Post Model contains all validation logic, so it’s not reusable for other entities, e.g., Admin. app/controller/posts_controller.rb
```
class PostsController < ApplicationController 
def create
@post = Post.new(post_params)

if @post. save
render json: @post 
else
     render json: @post.error, status: :unprocessable_entity 
   end 
end
private
def post_params
    params. require(: post).permit(:title, :description, :content)
   end
end

app/model/post.rb
class Post < ActiveRecord: :Base
    validates :title, presence: true
    validates : content, presence: true 
end
```
The better solution is to move the validation logic to a separate singular responsibility class that we might call PostForm:
```
class Post Form
include ActiveModel: :Model 
include Virtus.model

attribute :id, Integer 
attribute :title, String 
attribute :description, String 
attribute : content, String

attr_reader : record

def persist
     @record = id ? Post. find(id) : Post.new

    if valid?
      @record. save!
       true
    else
       false 
    end 
  end 
end
```
```
class PostsController < ApplicationController 
    def create
        @form = Post Form.new(post_params)

        if @form. persist
            render json: @form. record 
        else
            render json: @form.errors, status: :unpocessably_entity
        end
    end
private

def post_params
     params. require(: post).permit(:title, :description, :content)
   end
end
```
####  Value Object
The Value object is a type of Ruby pattern that encourages small, simple objects and allows you to compare these objects as per the given logic or specific attributes. It represents value but not something unique in your system like a user object. Value Objects always return only values

```
class EmailReport 
    def initialize(emails)
      @emails = emails
 end

def data
     emails_data = [ ]

emails.each do email| 
emails_data << {
     username: email.match(/([^@]*)/).to_s, 
     domain: email.split("@"). last
}
end

emails_data 
end

private 
attr_reader : emails
end
```
Now, let’s create the value object:
```
class Email 
    def initialize(email)
     @email = email 
end

def username
    email.match(/([^@]*)/).to_s 
end

def domain
    email.split("a"). last 
end

def to_h
    { username: username, domain: domain } 
end

private
attr_reader : email 
end
```
Calling Email values
```
class EmailReport 
    def initialize(emails: emails),
        @emails = emails 
   end

    def data
        emails.map { email| Email.new(email).to_h }
    end

    private
    attr_reader : emails 
end
```

#### Policy Object

The policy object is similar to the Service object; the only difference is policy object is responsible for the read operations, and the service object is responsible for write operations.

In rails, we use cancan or pundit gem for the authorization, but these gems are suitable if the application complexity is medium, 

If the application complexity is high (in terms of authorization), then, in that case, we use policy object for better efficiency. It returns a boolean value (true or false). 

```
class UserService 
    def initialize(user)
        @user = user
    end

    def name
        user_policy.take_email_as_name?? user.email : user.full_name
    end

    def account_name
        user_policy.is_admin? ? "Administrator": "User",
    end
    
    private 
    attr_reader : user

    def user_policy
        @_user_policy II = UserPolicy.new(user), 
    end
end
```
Let’s create a policy (app/policies/user_policy.rb):
```
class UserPolicy 
      def initialize(user)
        @user = user 
    end

    def is_admin?
         user_role_is_admin? 
    end

    def take_email_as_name?
        user_full_name_is_not_present? && is_user_email_present? 
    end

    private 
    attr_reader : user

    def user_full_name_is_not_present?
         user.full_name.blank? 
    end

    def is_user_email_present?
         user.email.present? 
    end

    def user_role_is_admin?
        user.sign_in_count > 0 && user.role == "admin" 
    end 
end
```

#### Observer
In this pattern, other interested objects are notified whenever an event has occurred. The observed object contains its observers’ list and notifies them by sending an update whenever its state changes

When you want to make several views changes manually
When an object’s state is dependent on a specific state
When several views are dependent on a particular object’s state
```
require 'observer'

class Product
  include Observable

  attr_reader :productName, :availableProducts

  def initialize(productName = "", availableProducts = 0)
    @productName, @availableProducts = productName, availableProducts
    add_observer(Notifier.new)
  end

  def update_availableProducts(product)
    @product = product
    changed
    notify_observers(self, product)
  end
end
```
Now, we will build a class which would be notified with the updates on available products.

```
class Notifier
  def update(product, availableProducts)
    puts "Yes, #{product.name} is available" if availableProducts > 0
    puts "Oops! Sorry, #{product.name} is unavailable!" if availableProducts == 0
  end
end
```

```
isProductAvailable = Product.new("Iphone 12")

isProductAvailable.update_availableProducts(5)
# => Yes, Iphone 12 is available

isProductAvailable.update_availableProducts(8)
# => Yes, Iphone 12 is available

isProductAvailable.update_availableProducts(0)
# => Oops! Sorry, Iphone 12 is unavailable
```


---

### Reverse Array
```
a = [1, 2, 3, 4, 5, 6]
left = 0
right = a.length - 1

while left < right
  # Swap the elements at the 'left' and 'right' indices
  a[left], a[right] = a[right], a[left]

  # Move the pointers towards the center
  left += 1
  right -= 1
end

puts a  # Output will be [6, 5, 4, 3, 2, 1]

```

---


### Query Optimisation technique
Query optimization is essential for the performance of any database-driven application, including those built on Ruby on Rails with Active Record. Here are some techniques and best practices for optimizing your queries:

1. **Select Only What You Need**:
   - Instead of fetching all columns with `Model.all`, use `select` to fetch only the columns you need.
     ```ruby
     User.select(:id, :name)
     ```

2. **Use Indexes**:
   - Index frequently queried columns to speed up search operations. However, avoid over-indexing as it can slow down write operations.

3. **Eager Loading with `includes` or `eager_load`**:
   - Helps to reduce the "N+1 query problem".
     ```ruby
     User.includes(:posts).where("posts.published = ?", true)
     ```

4. **Use `exists?` for Presence**:
   - Instead of `Model.any?` or `Model.count > 0`, use `Model.exists?` to check for a record's presence.

5. **Use Database Constraints**:
   - Utilize `UNIQUE`, `FOREIGN KEY`, and other constraints in the database to ensure data integrity without additional application-level checks.

6. **Limit and Offset**:
   - Use `limit` and `offset` to paginate results and avoid fetching more records than necessary.

7. **Caching**:
   - Use tools like Redis or Memcached to cache frequently accessed queries.

8. **Batch Processing**:
   - Use methods like `find_each` or `find_in_batches` for processing large sets of data.
     ```ruby
     User.find_each(batch_size: 100) do |user|
       # process each user
     end
     ```

9. **Avoid Ruby Iteration Over Large Data Sets**:
   - Instead of loading a large number of records and processing them in Ruby, try to handle as much data processing as possible in the database.

10. **Use SQL Views or Materialized Views**:
    - For complex queries that join several tables, consider using database views or materialized views.

11. **Be Mindful of Joins**:
    - Limit the number of `joins` in a query, as they can substantially slow down performance. Consider using `subqueries` when applicable.

12. **Optimize Database Configuration**:
    - Tools like the `pgtune` for PostgreSQL can help optimize the database configuration.

13. **Review Logs**:
    - Regularly check your development logs to spot inefficient queries.

14. **Database Tools and Extensions**:
    - Use tools like `EXPLAIN` (in SQL databases) to understand how your query is being executed and optimize accordingly.

15. **Keep Application and Database Updated**:
    - New versions often come with optimizations and improvements. Ensure you're using a well-maintained version of both your database and Rails.

16. **Use Counter Cache**:
    - Instead of running a `COUNT` query every time you need to know the number of associated records, use Rails' `counter_cache` feature.

17. **Avoid `default_scope`**:
    - `default_scope` in Rails can lead to unexpected behaviors and negatively impact performance. Use scopes with caution.

18. **De-normalization**:
    - In situations where read performance is crucial, consider de-normalizing the database to reduce the need for complex joins or calculations.

Remember, before making any optimizations, it's essential to identify the bottlenecks. Tools like `rack-mini-profiler`, `Bullet`, and database-specific profilers can be invaluable in this regard.


### SOLID

#### Single Responsibility Principle (SRP)
The Single Responsibility Principle dictates that a class should have only one reason to change, meaning it should have only one job or responsibility.
```ruby
# Good: Single responsibility of sending email
class EmailSender
  def send_email(email, content)
    # logic to send email
  end
end

# Bad: Multiple responsibilities
class UserManager
  def create_user(params)
    # logic to create user
  end

  def send_email(email, content)
    # logic to send email
  end
end

```

#### Open/Closed Principle (OCP)
According to the Open/Closed Principle, software entities (classes, modules, methods, etc.) should be open for extension but closed for modification.
```ruby
# Base class
class ReportGenerator
  def generate
    # common logic
  end
end

# Extended classes
class PDFReport < ReportGenerator; end
class XMLReport < ReportGenerator; end

```

#### Liskov Substitution Principle (LSP)
The Liskov Substitution Principle states that objects of a superclass should be able to be replaced with objects of a subclass without affecting the correctness of the program.
```ruby
class Bird
  def fly
    'I can fly'
  end
end

class Penguin < Bird
  def fly
    'I cannot fly'
  end
end
```
Here, a Penguin is-a Bird, but it violates LSP because it cannot fly, unlike other birds

#### Interface Segregation Principle (ISP)
The Interface Segregation Principle suggests that a class should not be forced to implement interfaces it does not use. In other words, don't add additional responsibilities to an existing class or module.

```ruby
# Good
class OrderProcessor
  def process_order; end
end

class PaymentProcessor
  def process_payment; end
end

# Bad
class OrderAndPaymentProcessor
  def process_order; end
  def process_payment; end
end

```

#### Dependency Inversion Principle (DIP)
The Dependency Inversion Principle states that high-level modules should not depend on low-level modules; both should depend on abstractions. Also, abstractions should not depend on details; details should depend on abstractions.

```ruby
# Good
class OrderProcessor
  def initialize(payment_gateway)
    @payment_gateway = payment_gateway
  end
end

# Bad
class OrderProcessor
  def initialize
    @payment_gateway = CreditCardPaymentGateway.new
  end
end

```
---
---

### Transactions
Transactions are a feature of databases that allow you to execute a series of Active Record operations atomically, meaning that either all the operations succeed, or none of them do. 

Transactions ensure data integrity and consistency even in situations where multiple operations need to occur in a sequence.

```ruby
User.transaction do
  user = User.new(username: 'John')
  user.save!

  profile = Profile.new(user: user, bio: 'Hello, world!')
  profile.save!
end

User.transaction do
  user = User.create(username: 'John')

  Profile.transaction do
    profile = Profile.create(user: user, bio: 'Nested transaction')
    raise ActiveRecord::Rollback if some_condition_not_met
  end
end


User.transaction do
  user.save!
  raise ActiveRecord::Rollback if some_condition_not_met
end

```

#### Why Use Transactions?
**Atomicity**: Ensures that a series of operations are atomic.
**Consistency**: Helps maintain database consistency.
**Isolation**: In a multi-user environment, ensures that operations from one transaction are isolated from another until committed.
**Durability**: Once committed, the changes are permanent.


### Eager Loading

One way to improve performance is to cut down on the number of SQL queries. You can do this through eager loading.

`User.find(:all, :include => :friends)`

Here you are firing only two queries :
1) One for all users.
2) One for all friends of users .

### Lazy Loading :

When you have an object associated with many objects like a User has many Friends and you want to display a list as in Orkut you fire as many queries as there are friends, plus one for the object itself.

```ruby
users = User.find(:all)
Then query for each user friend , like :

users.each do |user|
  friend = Friend.find_by_user_id(user.id)
end
```
1) One query for all users.
2) N query for N no. of users friends .

### CSRF (Cross-Site Request Forgery)

The CSRF (Cross-Site Request Forgery) mechanism in Ruby on Rails is designed to prevent unauthorized commands from being transmitted from a user that the web application trusts. Here's a brief overview of how Rails handles and validates the CSRF token to ensure this protection:

1. Token Generation:
    When you use form_for or other Rails form helpers, a hidden input field named authenticity_token is included in the generated form. This token is generated by the server.
    The same token is also stored in the session on the server side.

2. Sending the Token:
    For traditional form-based requests, the token is included as a hidden form field and thus sent as part of the form data.
    For AJAX requests, the token can be added as an HTTP header called X-CSRF-Token.

3. Validation:
    When the form is submitted or an AJAX request is made, Rails will expect the CSRF token to be present either in the form data or in the HTTP header.

    The server-side Rails framework retrieves the token from the session and compares it with the token sent with the request.
    If the tokens don't match or if the token is missing from the request, Rails will raise an `ActionController::InvalidAuthenticityToken` exception, thereby preventing the request from succeeding.

4. Configuring the CSRF Protection:
    In a Rails application, CSRF protection is enabled by default. You'll find the following line in the ApplicationController:
    `protect_from_forgery with: :exception`
    This means if a CSRF token is invalid or missing, an exception will be raised. However, you can also use with: :null_session if you want to reset the session instead of raising an exception.

**Use Cases**:
If for some reason you need to disable CSRF protection for specific actions or controllers (not typically recommended for web-facing routes due to security concerns), you can use skip_before_action :verify_authenticity_token.

Remember, CSRF attacks rely on the fact that browsers send cookies with every request, even if the request originates from a different site. By requiring a CSRF token, which is not automatically sent by browsers, Rails ensures that the request is made intentionally by the user and from the legitimate site.

### Find the overlapping sets and merge together in ruby on rails

```ruby
def merge_intervals(intervals)
  return [] if intervals.empty?

  # Sort intervals by start time
  intervals.sort_by! { |interval| interval[0] }

  merged = [intervals[0]]

  intervals[1..-1].each do |current_interval|
    last_merged = merged[-1]

    # If the current interval overlaps with the last merged interval
    if current_interval[0] <= last_merged[1]
      # Merge them
      last_merged[1] = [last_merged[1], current_interval[1]].max
    else
      # Otherwise, just add the current interval to the merged list
      merged << current_interval
    end
  end

  merged
end

input = [[80,120], [100, 160], [180, 240], [280,320], [300, 360], [340, 400]]
output = merge_intervals(input)
puts output.inspect
# This should output: [[80,160], [180, 240], [280,400]]

```