<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: FaxriddinMaxmadiyorov</title>
    <description>The latest articles on DEV Community by FaxriddinMaxmadiyorov (@faxriddinmaxmadiyorov).</description>
    <link>https://dev.to/faxriddinmaxmadiyorov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1240082%2F9a75719c-107b-4825-be9e-a0b6b7cbe039.jpeg</url>
      <title>DEV Community: FaxriddinMaxmadiyorov</title>
      <link>https://dev.to/faxriddinmaxmadiyorov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/faxriddinmaxmadiyorov"/>
    <language>en</language>
    <item>
      <title>What’s the Difference Between count, size, and length in Ruby and Ruby on Rails?</title>
      <dc:creator>FaxriddinMaxmadiyorov</dc:creator>
      <pubDate>Fri, 11 Jul 2025 16:06:20 +0000</pubDate>
      <link>https://dev.to/faxriddinmaxmadiyorov/count-vs-size-vs-length-in-ruby-566b</link>
      <guid>https://dev.to/faxriddinmaxmadiyorov/count-vs-size-vs-length-in-ruby-566b</guid>
      <description>&lt;p&gt;In plain Ruby, there’s effectively no difference between &lt;strong&gt;count&lt;/strong&gt;, &lt;strong&gt;size&lt;/strong&gt;, and &lt;strong&gt;length&lt;/strong&gt; when working with arrays or other collection-like objects — they all return the number of elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [1, 2, 3]
arr.count   # =&amp;gt; 3
arr.size    # =&amp;gt; 3
arr.length  # =&amp;gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in Ruby on Rails, particularly when dealing with &lt;strong&gt;ActiveRecord&lt;/strong&gt; associations or query objects, these methods behave very differently under the hood — especially in terms of performance and when they trigger database queries.&lt;/p&gt;

&lt;p&gt;Understanding these differences is crucial when you're working with large datasets or optimizing performance in a Rails application.&lt;/p&gt;

&lt;p&gt;Let's take an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users = User.where(active: true)
users.class # User::ActiveRecord_Relation # its returns ActiveRecord, does not execute the query in this stage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, users is an &lt;strong&gt;ActiveRecord::Relation&lt;/strong&gt;, not an array. That means the database query has not been executed yet — it's just a representation of the query to be run later.&lt;/p&gt;

&lt;p&gt;This is a key feature of &lt;strong&gt;ActiveRecord: lazy loading&lt;/strong&gt;. The query will only be executed when the data is actually needed — for example, when you iterate over the records, call &lt;strong&gt;.to_a&lt;/strong&gt;, or use &lt;strong&gt;.length&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  .count
&lt;/h2&gt;

&lt;p&gt;Since users is an &lt;strong&gt;ActiveRecord::Relation&lt;/strong&gt;, calling &lt;strong&gt;.count&lt;/strong&gt; on it will immediately execute a &lt;strong&gt;SQL COUNT(*)&lt;/strong&gt; query to count the number of matching records — without loading the actual records into memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[51] pry(main)&amp;gt; users.count
   (0.6ms)  SELECT COUNT(*) FROM "users" WHERE "users"."active" = $1 /*application:Pixie*/  [["active", true]]
=&amp;gt; 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is efficient when you only need the number of records, not the records themselves.&lt;/p&gt;

&lt;p&gt;Note: &lt;strong&gt;.count&lt;/strong&gt; always queries the database, even if the relation was previously loaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  .length
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;.length&lt;/strong&gt; method always loads the records into memory and then calculates the number of elements by calling &lt;strong&gt;Array#length&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users = User.where(active: true)
users.length  # =&amp;gt; runs SELECT * FROM users WHERE active = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts the relation into an array and then returns the number of elements.&lt;/p&gt;

&lt;p&gt;Important: This can be inefficient for large datasets because it loads all matching records into memory, even if you only need the count.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;.length&lt;/strong&gt; only when you actually need the full records — for example, if you're going to iterate over them right after.&lt;/p&gt;

&lt;h2&gt;
  
  
  .size
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;.size&lt;/strong&gt; method is smart — it adapts based on whether the records have already been loaded into memory.&lt;/p&gt;

&lt;p&gt;If the records are already loaded, .size simply returns the number of records in memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users.loaded?
# =&amp;gt; true

users.size
# =&amp;gt; 32  (No additional SQL query is executed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the records are not yet loaded, .size behaves like .count and runs a &lt;strong&gt;SQL COUNT(*)&lt;/strong&gt; query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;users.loaded?
# =&amp;gt; false

users.size
# =&amp;gt; Executes:
# SELECT COUNT(*) FROM "users" WHERE "users"."active" = $1
# =&amp;gt; 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes &lt;strong&gt;.size&lt;/strong&gt; the most efficient and flexible choice in many cases — it avoids unnecessary queries but still gives an accurate count.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Chat Server in Ruby Sockets</title>
      <dc:creator>FaxriddinMaxmadiyorov</dc:creator>
      <pubDate>Sun, 28 Jul 2024 18:14:48 +0000</pubDate>
      <link>https://dev.to/faxriddinmaxmadiyorov/sockets-in-ruby-36c5</link>
      <guid>https://dev.to/faxriddinmaxmadiyorov/sockets-in-ruby-36c5</guid>
      <description>&lt;p&gt;I am going to build a chat server in Ruby's sockets library. Before this, let's clarify what sockets are. Sockets are the endpoints of the communication channels. There are two types of sockets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stream sockets - These sockets use Transmission Control Protocol (TCP) for communication. They provide a reliable, connection-oriented communication channel. Web servers and clients (HTTP/HTTPS) use this kind of sockets.&lt;/li&gt;
&lt;li&gt;Datagram sockets - These sockets use User Datagram protocol for communication. They are less reliable than TCP sockets and are used in streaming.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Chat application contains two parts: server and client; We will organize server part first:&lt;br&gt;
Create TCPServer, it accepts infinite signals, i.e it must be alive, exchange data.&lt;br&gt;
Create Socket client, it connects to server, exchange data&lt;/p&gt;

&lt;p&gt;Our first example shows synchronous chat (chat and clients sides have to wait each other to send a message, each side of the connection waits for the other to send a message before it proceeds, creating a sort of "deadlock" where both sides are waiting.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# server.rb
require 'socket'

server = TCPServer.new('localhost', 3333)
puts "TCPServer is running port on 3333 ..."

client = server.accept
puts "Client connected."

loop do
  message = client.gets.chomp
  puts "Client: #{message}"
  break if message == 'exit'

  response = gets.chomp
  client.puts response
  break if response == 'exit'
end

client.close
puts "Client disconnected."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# client.rb
require 'socket'

client = TCPSocket.new('localhost', 3333)
puts "Connected to server..."

loop do
  message = gets.chomp
  client.puts message

  # Exit if the message is 'exit'
  break if message == 'exit'

  # Receive and print the server's response
  response = client.gets.chomp
  puts "Server: #{response}"
  break if response == 'exit'
end

client.close
puts "Disconnected from server."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To deliver messages in correct order, we have to use Threads to handle other tasks concurrently (the server accepts only one client).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'socket'

server = TCPServer.new('localhost', 3333)
puts "TCPServer is running port on 3333 ..."

client = server.accept
puts "Client connected."

# Thread to handle reading messages from the client
Thread.new do
  loop do
    message = client.gets.chomp
    puts "Client: #{message}"
    break if message == 'exit'
  end
end

# Thread to handle sending messages to the client
loop do
  response = gets.chomp
  client.puts response
  break if response == 'exit'
end

client.close
puts "Client disconnected."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require 'socket'

client = TCPSocket.new('localhost', 3333)
puts "Connected to server..."

# Thread to reading messages from the server
Thread.new do
  loop do
    message = client.gets.chomp
    puts "Server: #{message}"
    break if message == 'exit'
  end
end

loop do
  response = gets.chomp
  client.puts response
  break if response == 'exit'
end

client.close
puts "Disconnected from server."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want our server can communicate to all clients at the same time, we should create 1 thread (to handle communication) for each client and 1 server thread (to handle server-side input and broadcasts). As to client side, we have to create one thread to handle incoming message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# server.rb
require 'socket'

server = TCPServer.new('localhost', 3333)
puts "TCPServer is running on port 3333 ..."

clients = []

def broadcast(message, clients, sender = nil)
  clients.each do |client|
    client.puts message unless client == sender
  end
end

# Thread to handle server input
server_input_thread = Thread.new do
  loop do
    response = gets
    break if response.nil? || response.chomp == 'exit'

    message = "Server: #{response.chomp}"
    broadcast(message, clients)
  end
  puts "Server shutting down."

  clients.each { |client| client.close } # Close all client connections
  server.close
  exit
end

loop do
  client = server.accept
  clients &amp;lt;&amp;lt; client
  puts "Client connected."

  Thread.new(client) do |client_socket|
    begin
      loop do
        message = client_socket.gets
        break if message.nil? || message.chomp == 'exit'

        message = "Client: #{message.chomp}"
        puts message
      end
    rescue StandardError
      puts "Client disconnected."
    ensure
      clients.delete(client_socket)
      client_socket.close
      puts "Client disconnected."
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# client.rb
require 'socket'

client = TCPSocket.new('localhost', 3333)
puts "Connected to server..."

# Thread to reading messages from the server
Thread.new do
  loop do
    message = client.gets&amp;amp;.chomp
    puts message
    break if message == 'exit'
  end
end

loop do
  response = gets.chomp
  client.puts response
  break if response == 'exit'
end

client.close
puts "Disconnected from server."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>socket</category>
      <category>tcp</category>
      <category>ruby</category>
    </item>
    <item>
      <title>SOLID Design Principles in Ruby</title>
      <dc:creator>FaxriddinMaxmadiyorov</dc:creator>
      <pubDate>Tue, 02 Jul 2024 04:57:04 +0000</pubDate>
      <link>https://dev.to/faxriddinmaxmadiyorov/solid-principles-in-ruby-49p7</link>
      <guid>https://dev.to/faxriddinmaxmadiyorov/solid-principles-in-ruby-49p7</guid>
      <description>&lt;p&gt;&lt;strong&gt;SOLID - dasturni yanada tushunarli, o'zgartirishga va kattalashtirishga imkon beruvchi principlar yig'indisi.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single Responsibility Principle (SRP)&lt;/li&gt;
&lt;li&gt;Open/Closed Principle (OCP)&lt;/li&gt;
&lt;li&gt;Liskov Substitution Principle (LSP)&lt;/li&gt;
&lt;li&gt;Interface Segregation Principle (ISP)&lt;/li&gt;
&lt;li&gt;Dependency Inversion Principle (DIP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;1. Single Responsibility Principle&lt;/strong&gt;&lt;br&gt;
Har bir class faqatgina bitta funksionalga javob berishi kerak. Ko'p funksional'larni bitta class'da yozilgan bo'lsa, o'sha classni o'zgartirish hamma funksionallarni o'zgartirishga olib kelishi mumkin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Employee
  def process_data
  end

  def send_message(message)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;masalan, bizda Employee class bor, unda process_data va send_message method'lari mavjud. send_message method'ga o'zgartirish kerak bo'lsa, Employee classni ichida o'zgartirishga to'g'ri keladi. Bundan tashqari, mijozlarga ham message yuborish kerak bo'lsa, Client class'ni ichida ham send_message methodini yozishimizga to'g'ri keladi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Employee
  def process_data; end
end

class Client
  def process_data; end
end

class Message
  def send_message(user, message)
  end
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agar yuboriladigan message o'zgartirilishi kerak bo'lsa, Message classni ichida o'zgartirishimiz kifoya.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Open/Closed Principle (OCP)&lt;/strong&gt;&lt;br&gt;
Classlar kengaytirish uchun ochiq, lekin o'zgartirish yoki refaktor qilish uchun yopiq bo'lishi kerak. Bu printsip classni imkoniyatini oshirish uchun allaqachon ishlab turgan classni o'zgartirmaslikni eslatadi. Masalan bizda InvoiceReport class bor, u hozircha orderni pdf va csv formatlarda generate qiladi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class InvoiceReport
  def initialize(order, type)
    @order = order
    @type = type
  end

  def generate
    case @type
    when 'pdf'
      # pdf generation
    when 'csv'
      # csv generation
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Endi xls formatda ham report generate qilmoqchimiz, va InvoiceReport classga qo'shishimiz kerak. Buni oldini olish uchun Open/Closed Principle ishlatishimiz mumkin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class InvoiceReport
  def initialize(order, klass)
    @order = order
    @klass = klass
  end

  def generate
    @klass.new(@order).generate
  end
end

class PdfGenerator
  def initialize(order)
    @order = order
  end

  def generate
    # Generate PDF report
    puts "PDF Report generated"
  end
end

class CsvGenerator
  def initialize(order)
    @order = order
  end

  def generate
    # Generate CSV report
    puts "CSV Report generated"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Liskov Substitution Principle&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;if S could be a sub-type of T, then objects of type T is also replaced with objects of type S&lt;/strong&gt; - Agar S class T classni child classi bo'lsa, T classni obyektlari S classni obyektlari bilan muvofiq bo'lishi kerak.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def report
    raise 'Not implemented for User class'
  end
end

class Employee &amp;lt; User
  def initialize(name)
    super
  end

  def report
    puts "Report method called!!!"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agar child class o’zining ota class’i bilan bir xil amallarni bajara olmasa, bu xatolarga olib kelishi mumkin.&lt;/p&gt;

&lt;p&gt;Agar sizda class mavjud bo’lsa va undan yangi yangi class yaratsangiz, u parent (ota) va yangi class esa child (farzand) class bo’ladi. Child class ota class bajara olgan barcha narsani qila olishi kerak. Bu jarayon Inheritance deyiladi.&lt;/p&gt;

&lt;p&gt;Child class bir xil so’rovlarni qayta ishlashi va parent class bilan bir xil yoki bir turdagi natijani berishi kerak.&lt;/p&gt;

&lt;p&gt;Ushbu tamoyil asosiy sinf yoki uning pastki sinfi hech qanday xatosiz bir xil tarzda ishlatilishi uchun o’zgarmaslikni ta’minlashga qaratilgan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Interface Segregation&lt;/strong&gt;&lt;br&gt;
Interface Segregation tamoyili client ishlatmaydigan methodga bog'liq bo'lmasligini aytadi. Boshqacha qilib aytganda, bitta umumiy katta interfeysdan ko'ra classni o'zigagina tegishli interfeyslar yaratish g'oyasini qo'llaydi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module PrinterFunctions
  def print

  end

  def scan

  end

  def fax

  end
end

class Printer
  include PrinterFunctions
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;hamma printerlar scan yoki fax funksiyasini qo'llab quvvatlay olmaydi, va bu misol ISP ni buzadi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module PrintFunctions
  def print

  end
end

module ScanFunctions
  def scan

  end
end

module FaxFunctions
  def fax

  end
end

class Samsung
  include PrintFunctions
  include ScanFunctions
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Endi client o'ziga kerakli methodlarni ishlata oladi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Dependency Inversion Principle&lt;/strong&gt;&lt;br&gt;
High-level class'lar low level class'larga qaram bo'lmasligi kerak. Har ikkalasi ham abstraktsiyaga qaram bo'lishi kerak. Dependency Inversion Liskov Substitution and Open-Closed principlari jamlanmasi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class NotificationService
  def notify_via_email(message)
    # EmailNotifier classga to'g'ridan to'g'ri bog'liq
    email_notifier = EmailNotifier.new
    email_notifier.send_email(message)
  end
end

class EmailNotifier
  def send_email(message)
    puts "Sending email with message: #{message}"
    # Logic to send an email
  end
end

notification_service = NotificationService.new
notification_service.notify_via_email('Hello via Email!')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;bu yerda muammolar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;NotificationService EmailNotifier classga bog'liqligi&lt;/li&gt;
&lt;li&gt;Yangi Notification type qo'shmoqchi bo'lsak, NotificationService classga o'zgartirish kiritishga to'g'ri keladi.
Bu muammolarni Dependency Inversion prinsipiga binoan hal qilsak:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# notifier.rb, Abstraksiya yaratish
module Notifier
  def send_message(message)
    raise NotImplementedError, 'You must implement the send_message method'
  end
end

class EmailNotifier
  include Notifier

  def send_message(message)
    puts "Sending email with message: #{message}"
    # Logic to send an email
  end
end

# notification_service.rb, Notifier abstraksiyasini ishlatish
class NotificationService
  def initialize(notifier)
    @notifier = notifier
  end

  def notify(message)
    @notifier.send_message(message)
  end
end

email_notifier = EmailNotifier.new
notification_service = NotificationService.new(email_notifier)
notification_service.notify('Hello via Email!')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu bilan yuqori darajadagi class undan pastroq darajadagi classga bog'liq bo'lmaydi.&lt;/p&gt;

</description>
      <category>solid</category>
      <category>ruby</category>
      <category>oop</category>
    </item>
    <item>
      <title>PayPal REST API</title>
      <dc:creator>FaxriddinMaxmadiyorov</dc:creator>
      <pubDate>Sat, 13 Apr 2024 08:48:31 +0000</pubDate>
      <link>https://dev.to/faxriddinmaxmadiyorov/paypal-rest-api-3pi6</link>
      <guid>https://dev.to/faxriddinmaxmadiyorov/paypal-rest-api-3pi6</guid>
      <description>&lt;p&gt;In this article, I will explain how to integrate the PayPal REST API. First of all, we should create a sandbox account on PayPal at developer.paypal.com.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlwqqyzekje839ajblmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlwqqyzekje839ajblmz.png" alt="Image description" width="800" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;br&gt;
As written in the documentation, we have 2 options to authenticate our request to sandbox server:&lt;/p&gt;

&lt;p&gt;get a bearer token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token"\
 -u "CLIENT_ID:CLIENT_SECRET"\
 -H "Content-Type: application/x-www-form-urlencoded"\
 -d "grant_type=client_credentials"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;encryption of CLIENT_ID:CLIENT_SECRET in Base64&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Base64.strict_encode64("#{PAYPAL_CLIENT_ID}:#{PAYPAL_CLIENT_SECRET}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will get access_token in both ways. I will write business logic in active interactions.&lt;/p&gt;

&lt;p&gt;We need to set 2 endpoints to proceed a payment with Paypal: 1) create order 2) execute order;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Order&lt;/strong&gt;&lt;br&gt;
We should create an order; &lt;/p&gt;

&lt;p&gt;create_order.rb&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_path = BASE_URL + '/v2/checkout/orders'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two options for intent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AUTHORIZE&lt;/li&gt;
&lt;li&gt;CAPTURE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you set the intent to "AUTHORIZE," PayPal authorizes the payment amount but doesn't capture the funds immediately. Instead, it places a hold on the funds, reserving them for capture at a later time. This is useful in scenarios where you need to verify the availability of funds or perform additional checks before completing the transaction.&lt;br&gt;
Use Case: For example, if you operate an e-commerce platform, you might use the "AUTHORIZE" intent when a customer places an order. This allows you to verify the payment details and inventory availability before confirming the purchase and capturing the funds.&lt;/p&gt;

&lt;p&gt;CAPTURE: With the "CAPTURE" intent, PayPal immediately captures the funds from the customer's account when the payment is made. This completes the transaction in real-time, and the funds are transferred to your account.&lt;br&gt;
Use Case: In scenarios where you provide digital goods or instant services, using the "CAPTURE" intent ensures that payments are processed and funds are transferred immediately upon completion of the transaction.&lt;/p&gt;

&lt;p&gt;If we create an order with "AUTHORIZE" intent, then we have to authorize (&lt;strong&gt;Authorize Order&lt;/strong&gt; method, &lt;strong&gt;Orders API&lt;/strong&gt;) the order then capture the order (&lt;strong&gt;Capture Authorized Payment&lt;/strong&gt;, &lt;strong&gt;Payments API&lt;/strong&gt;); If we create an order with "CAPTURE" intent, then we directly use &lt;strong&gt;Capture Payment&lt;/strong&gt; for Order method (&lt;strong&gt;Orders API&lt;/strong&gt;);&lt;/p&gt;

&lt;p&gt;We will use "CAPTURE" intent here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CAPTURE&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_path = BASE_URL + '/v2/checkout/orders/{id}/capture'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that is all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subscriptions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When we visit Netflix.com, we can see monthly plans; Every month, some money is withdrawn from our card. How can it happen by itself? Here comes webhooks. A webhook is an HTTP request triggered by an event in a source system and sent to a destination system. When money is withdrawn, PayPal sends a notification to our server. We need an endpoint to receive a POST request from Paypal and add it in "Add Webhook" section. It is not possible to set localhost url, if you want to test in your localhost, then you can use ngrok. We need to return a response with 200 status code if everything is ok, else failure. Otherwise it keeps sending a request to our server.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iall1abg2g84ajhfyno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iall1abg2g84ajhfyno.png" alt="Image description" width="800" height="472"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class WebhooksController &amp;lt; ApplicationController
  skip_before_action :verify_authenticity_token, only: :checkout_webhook

  def checkout_webhook
    render plain: '', status: :ok
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Product and Plan should be created for a Subscription. &lt;/p&gt;

&lt;p&gt;create_product.rb&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_path = BASE_URL + '/v1/catalogs/products'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create_plan.rb&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_path = BASE_URL + '/v1/billing/plans'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create_subscription.rb&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request_path = BASE_URL + '/v1/billing/subscriptions'
HTTParty.post(request_path, headers: headers, body: your_body.to_json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After subscription is created successfully, its status will be &lt;strong&gt;APPROVAL_PENDING&lt;/strong&gt;. After clicking the button, the status will be active.&lt;/p&gt;

</description>
      <category>paypal</category>
      <category>restapi</category>
      <category>ruby</category>
      <category>webhooks</category>
    </item>
  </channel>
</rss>
