<?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>Forem: Shaher Shamroukh</title>
    <description>The latest articles on Forem by Shaher Shamroukh (@shahershamroukh).</description>
    <link>https://forem.com/shahershamroukh</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%2F508938%2Fefe537b8-9331-4eac-8b13-c281a374d877.jpeg</url>
      <title>Forem: Shaher Shamroukh</title>
      <link>https://forem.com/shahershamroukh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shahershamroukh"/>
    <language>en</language>
    <item>
      <title>AI Can Write Code But It Still Can’t Think Like a Developer</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Wed, 07 Jan 2026 17:32:16 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/ai-can-write-code-but-it-still-cant-think-like-a-developer-18pb</link>
      <guid>https://forem.com/shahershamroukh/ai-can-write-code-but-it-still-cant-think-like-a-developer-18pb</guid>
      <description>&lt;p&gt;Everyone is talking about AI replacing developers. Some say junior devs won’t even find jobs in 2026. As someone running a dev team at RobinReach, I think this is overblown and here’s why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing Code Is Not the Same as Solving Problems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lot of people think coding is just typing lines of code or building a simple website. Real software development is way more than that. You have to understand what a feature should actually do, how it should behave in tricky situations, track down bugs and find the root cause, design a system that is scalable and maintainable, and make decisions about trade-offs between speed, performance, security, and user experience.&lt;/p&gt;

&lt;p&gt;And when it comes to full web apps, it gets even more complex. You are not just writing HTML or CSS. You have databases, backend logic, routing, state management, APIs, integrations, and frontend frameworks. AI cannot grasp the full system in context or reason about how all the pieces interact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static Websites Versus Full Web Apps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where people get confused. A static website is something simple, like a landing page or portfolio. You can set up a WordPress site or a Wix page in a couple of hours without any AI. It’s straightforward and there is nothing revolutionary about AI doing the same thing a little faster.&lt;/p&gt;

&lt;p&gt;Full web apps are a different story. They have databases, backend logic, authentication, APIs, dynamic routing, state management, error handling, and scaling. Building and maintaining these apps requires problem-solving, debugging, and architectural thinking. AI is not ready to do that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Research Says&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A recent MIT CSAIL study reported by IBM Think confirms this. It says that AI can churn out code but cannot think like a software engineer. AI struggles with planning long-term code, understanding an entire codebase, and handling legacy systems or specialized libraries.&lt;/p&gt;

&lt;p&gt;Even the best AI does not remember previous prompts or understand how a project evolves over time. AI can write code but it cannot replace the reasoning, problem-solving, and judgment that real developers provide.&lt;/p&gt;

&lt;p&gt;You can read the full article here: &lt;a href="https://www.ibm.com/think/news/ai-write-code-can-beat-software-engineers" rel="noopener noreferrer"&gt;IBM Think – AI can write code, but can it beat software engineers?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My Experience at &lt;a href="https://robinreach.com/" rel="noopener noreferrer"&gt;RobinReach&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even with AI tools, my junior developer drives the AI, not the other way around. They review suggestions, debug issues, validate fixes, and make architectural decisions. AI speeds up repetitive work but the thinking, problem-solving, and judgment are still fully human.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Future of Development&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The future is not AI replacing developers. It is humans working with AI. Developers who learn to use AI effectively will be faster and more productive. But understanding systems, reasoning through problems, and building robust software will always be human work.&lt;/p&gt;

&lt;p&gt;Are we overestimating AI, or is the future really about developers guiding AI to solve real software problems?&lt;/p&gt;

</description>
      <category>coding</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Managing Multiple Brands in Rails: Multi-Tenant Patterns from RobinReach</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Mon, 22 Dec 2025 20:47:02 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/managing-multiple-brands-in-rails-multi-tenant-patterns-from-robinreach-10ln</link>
      <guid>https://forem.com/shahershamroukh/managing-multiple-brands-in-rails-multi-tenant-patterns-from-robinreach-10ln</guid>
      <description>&lt;p&gt;Scaling a SaaS application is one thing; letting a single user manage multiple brands, each with its own isolated data, is another. &lt;br&gt;
At &lt;strong&gt;RobinReach&lt;/strong&gt;, we faced this challenge head-on: users needed to handle multiple workspaces, each with its own social profiles, posts, and team members, all while switching seamlessly between them. &lt;br&gt;
Here’s how we built it in Rails, and the lessons learned along the way.&lt;/p&gt;

&lt;p&gt;The Challenge: &lt;strong&gt;Multi-Brand Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine a user managing three different companies on your platform. Each company has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its own social media profiles&lt;/li&gt;
&lt;li&gt;Scheduled posts&lt;/li&gt;
&lt;li&gt;Team members and roles&lt;/li&gt;
&lt;li&gt;Analytics and performance data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without proper isolation, cross-tenant data leaks become a nightmare. &lt;br&gt;
Multi-tenancy is not just a database pattern, it’s a mindset for every layer of your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workspace-Based Multi-Tenancy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At &lt;strong&gt;RobinReach&lt;/strong&gt;, we modeled each brand or workspace as a tenant. All core models—Posts, SocialProfiles, Members, are scoped to a tenant. We use a thread-safe Current object to hold the tenant context:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;class Current &amp;lt; ActiveSupport::CurrentAttributes&lt;br&gt;
  attribute :company&lt;br&gt;
end&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This allows all models to reference the current tenant easily:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;class Post &amp;lt; ApplicationRecord&lt;br&gt;
  belongs_to :company&lt;br&gt;
  default_scope { where(company_id: Current.company.id) }&lt;br&gt;
end&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
With this pattern, every query automatically respects tenant boundaries.&lt;/p&gt;

&lt;p&gt;Seamless Workspace Switching&lt;/p&gt;

&lt;p&gt;Users expect to switch between workspaces without logging out. We store the current workspace in the session:&lt;br&gt;
&lt;code&gt;def switch_workspace(company_id)&lt;br&gt;
  session[:current_company_id] = company_id&lt;br&gt;
  Current.company = Company.find(company_id)&lt;br&gt;
end&lt;/code&gt;&lt;br&gt;
This ensures that every action like viewing posts, scheduling content, or managing members, is scoped correctly to the selected workspace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background Jobs in a Multi-Tenant Environment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Multi-tenancy isn’t just about database queries; background jobs must also respect tenant boundaries. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned:&lt;/strong&gt;&lt;br&gt;
Always pass the tenant ID to background jobs.&lt;/p&gt;

&lt;p&gt;Make jobs idempotent to prevent cross-tenant side effects.&lt;/p&gt;

&lt;p&gt;Use Sidekiq queues strategically; high-volume tenants might need separate queues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Practices for Workspace Multi-Tenancy&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforce tenant isolation at all layers – models, services, jobs, and controllers.&lt;/li&gt;
&lt;li&gt;Use thread-safe context objects (Current) for tenant information.&lt;/li&gt;
&lt;li&gt;Design for fast workspace switching in the UI.&lt;/li&gt;
&lt;li&gt;Keep background jobs idempotent and tenant-aware.&lt;/li&gt;
&lt;li&gt;Cache per tenant when appropriate to reduce database load.&lt;/li&gt;
&lt;li&gt;Monitor performance per workspace to detect heavy tenants early.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building a multi-brand SaaS in Rails isn’t just a technical challenge, it’s a design mindset.&lt;br&gt;
RobinReach demonstrates that with careful scoping, background job design, and workspace isolation, you can deliver a seamless multi-tenant experience.&lt;/p&gt;

&lt;p&gt;For Rails developers building SaaS platforms, these patterns can save you from future headaches and set your app up for scale.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>rails</category>
      <category>saas</category>
    </item>
    <item>
      <title>Building an AI Social Media Manager with Ruby on Rails: Architecture, Automation, and Lessons Learned</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Thu, 23 Oct 2025 19:56:33 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/building-an-ai-social-media-manager-with-ruby-on-rails-architecture-automation-and-lessons-3lpj</link>
      <guid>https://forem.com/shahershamroukh/building-an-ai-social-media-manager-with-ruby-on-rails-architecture-automation-and-lessons-3lpj</guid>
      <description>&lt;p&gt;Building an AI Social Media Manager with Ruby on Rails: Architecture, Automation, and Lessons Learned&lt;/p&gt;

&lt;p&gt;In a previous post, &lt;a href="https://dev.to/shahershamroukh/how-were-building-a-social-media-empire-with-rails-and-sidekiq-5p0"&gt;How We’re Building a Social Media Empire with Rails and Sidekiq&lt;/a&gt;, &lt;br&gt;
I shared how we scaled background jobs and task automation using Rails and Sidekiq. That article focused on how &lt;a href="https://robinreach.com/" rel="noopener noreferrer"&gt;RobinReach&lt;/a&gt;&lt;br&gt;
Our social media management platform handled large-scale post scheduling and media processing.&lt;/p&gt;

&lt;p&gt;This time, we’re taking a deeper dive into how we integrated AI into our architecture and how Ruby on Rails continues to be the backbone of everything we build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Rails Still Works for AI SaaS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even in 2025, Ruby on Rails remains a perfect fit for startups building fast, scalable, and flexible SaaS products. When we started building RobinReach, we needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move fast with a clean architecture.&lt;/li&gt;
&lt;li&gt;Handle complex background automation.&lt;/li&gt;
&lt;li&gt;Support multi-tenant data isolation for agencies.&lt;/li&gt;
&lt;li&gt;Integrate AI models that evolve quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rails gave us that foundation. With Hotwire and Tailwind CSS, we kept the frontend lean and responsive, no heavy SPAs needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our Service-Driven Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of our early decisions was to adopt a service-driven architecture. Every core component from AI post generation to video rendering lives inside a dedicated service class.&lt;/p&gt;

&lt;p&gt;That means each domain (posts, media, analytics, automation) can evolve independently while staying testable and predictable.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Ai::ContentGeneratorService
 def initialize(post)
  @post = post
 end

 def call
  prompt = "Create a social media caption about #{@post.topic} in an engaging tone."
  response = RubyLLM::Client.new(model: "gpt-4o-    mini").complete(prompt)
 @post.update!(caption: response.text)
 end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By keeping logic inside services, we avoid bloated models and controllers, and it makes it easy to reuse across background jobs.&lt;/p&gt;

&lt;p&gt;Using AI for Content Refinement&lt;/p&gt;

&lt;p&gt;We started with the ruby-openai gem, but later switched to ruby-llm for its flexibility and broader model support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our AI layer powers features like:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RobinGen → generates captions, hashtags, and text variations.&lt;/li&gt;
&lt;li&gt;RobinPilot → automates post creation from articles or ideas.&lt;/li&gt;
&lt;li&gt;Content refinement → rewrites existing drafts to fit platform tone (LinkedIn, Instagram, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The workflow is simple:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User drafts or uploads content.&lt;/li&gt;
&lt;li&gt;AI refines tone, grammar, or platform style.&lt;/li&gt;
&lt;li&gt;User reviews and approves before scheduling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use background jobs to handle API calls asynchronously, ensuring the dashboard stays responsive while posts are being “AI-polished.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Media Handling with MiniMagick and FFmpeg&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For visuals, we rely on MiniMagick for image resizing and Streamio-FFmpeg for short-form video generation. These two tools help us dynamically create social media content that looks like it was edited manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Tenant Design for Agencies and Brands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RobinReach was designed for both businesses and marketing agencies. Each company account can manage multiple brands, each brand having its own users, social profiles, posts, and analytics.&lt;/p&gt;

&lt;p&gt;We use a company context service to isolate data automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every query is scoped by company.&lt;/li&gt;
&lt;li&gt;Each background job inherits that context.&lt;/li&gt;
&lt;li&gt;Admins can switch between brands instantly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach ensures data security and scalability without introducing unnecessary complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lessons Learned Building RobinReach&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI integration works best when it’s optional and assistive, not intrusive.&lt;/li&gt;
&lt;li&gt;Service objects keep Rails clean and maintainable as complexity grows.&lt;/li&gt;
&lt;li&gt;Multi-tenancy needs clear boundaries early, retrofitting it later is painful.&lt;/li&gt;
&lt;li&gt;Rails still excels when paired with modern, lightweight tools like Hotwire and Tailwind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Closing Thoughts&lt;/p&gt;

&lt;p&gt;Building RobinReach has been a continuous learning process. We’ve learned that Rails is still one of the best frameworks for quickly turning complex ideas, like AI-driven automation, into production-ready features.&lt;/p&gt;

&lt;p&gt;Our next steps include making RobinReach’s AI even smarter, from better content understanding to predicting the best times to post.&lt;/p&gt;

&lt;p&gt;If you’d like to follow our journey or see how AI can simplify your social media workflow, you can check out RobinReach at &lt;a href="https://robinreach.com/en" rel="noopener noreferrer"&gt;https://robinreach.com/en&lt;/a&gt;&lt;br&gt;
.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>architecture</category>
      <category>ai</category>
    </item>
    <item>
      <title>How We’re Building a Social Media Empire with Rails and Sidekiq</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Tue, 05 Aug 2025 21:23:22 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/how-were-building-a-social-media-empire-with-rails-and-sidekiq-5p0</link>
      <guid>https://forem.com/shahershamroukh/how-were-building-a-social-media-empire-with-rails-and-sidekiq-5p0</guid>
      <description>&lt;p&gt;It’s been a minute since I last published a blog post, mostly because we’ve been busy building &lt;a href="https://robinreach.com/en" rel="noopener noreferrer"&gt;RobinReach&lt;/a&gt;, a modern social media management platform powered by Ruby on Rails.&lt;/p&gt;

&lt;p&gt;If you’ve ever tried building a tool that posts to multiple social platforms, handles different time zones, supports team approvals, automates publishing, and still provides clean analytics… you know it’s not a walk in the park.&lt;/p&gt;

&lt;p&gt;What could’ve easily turned into a tangled mess of conditionals, platform-specific logic, and fragile scheduling code became a clean, maintainable, and scalable system thanks to Rails' service-oriented design and Sidekiq for background job handling.&lt;/p&gt;

&lt;p&gt;The Stack That Powers RobinReach&lt;br&gt;
RobinReach runs on a streamlined and modern Rails stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby on Rails 7&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Sidekiq + Redis for background jobs&lt;/li&gt;
&lt;li&gt;Hotwire + Stimulus for reactive UI&lt;/li&gt;
&lt;li&gt;TailwindCSS for styling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We manage thousands of scheduled posts across platforms like Instagram, LinkedIn, TikTok, Twitter, and YouTube, all orchestrated through Sidekiq workers that handle everything from publishing to AI content generation.&lt;/p&gt;

&lt;p&gt;🧩 Why a Service-Oriented Architecture?&lt;br&gt;
Each social media platform comes with its own rules: different APIs, content requirements, authentication flows, error handling, rate limits, the list goes on.&lt;/p&gt;

&lt;p&gt;Instead of cluttering models or controllers with conditional logic, we split the logic by platform using dedicated service classes, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module SocialMedia
  module InstagramDirect
    class Post &amp;lt; SocialMedia::ApplicationService
      def initialize(post, profile)
        # setup context
      end

      def call
        # 1. create media container
        # 2. wait for readiness
        # 3. publish
        # 4. return success or failure
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the same structure for:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SocialMedia::Twitter::Service&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;SocialMedia::LinkedIn::Service&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Each class is responsible for only one job: posting to its platform.&lt;/p&gt;

&lt;p&gt;What This Gives Us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean interface: &lt;code&gt;PlatformService.new(post, profile).call&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Separation of concerns&lt;/li&gt;
&lt;li&gt;Platform-specific logging + error handling&lt;/li&gt;
&lt;li&gt;Easier testing, mocking, and maintenance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⏱ Why Sidekiq?&lt;/p&gt;

&lt;p&gt;Publishing a post isn’t instant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It needs to go out at the scheduled time&lt;/li&gt;
&lt;li&gt;Some platforms require polling&lt;/li&gt;
&lt;li&gt;Others need multi-step media uploads&lt;/li&gt;
&lt;li&gt;You don’t want users waiting for any of that&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Welcome Sidekiq.&lt;/p&gt;

&lt;p&gt;We use Sidekiq to handle everything asynchronously and at scale.&lt;/p&gt;

&lt;p&gt;A Typical Flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User schedules a post for a future time&lt;/li&gt;
&lt;li&gt;We enqueue the job like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;PostJob.perform_at(post.publish_time, post.id)&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The job runs, finds the post, and calls the right service object&lt;/li&gt;
&lt;li&gt;Everything happens in the background, with automatic retries if things fail.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡The Sweet Spot: Service + Sidekiq&lt;br&gt;
Here’s why the combination is so powerful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔧 Service Objects&lt;/strong&gt;            &lt;strong&gt;⏱ Sidekiq&lt;/strong&gt;&lt;br&gt;
Encapsulate platform logic  Handles execution &amp;amp; timing&lt;br&gt;
Keep jobs thin                  Makes everything async&lt;br&gt;
Testable, predictable           Retryable, resilient&lt;br&gt;
Modular per platform            Scalable with queues&lt;/p&gt;

&lt;p&gt;We can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add new platforms without touching existing logic&lt;/li&gt;
&lt;li&gt;Retry failed posts automatically&lt;/li&gt;
&lt;li&gt;Track errors in logs or monitoring tools&lt;/li&gt;
&lt;li&gt;Move fast without fearing regression&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🧪 Testability Bonus&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each service object is unit-tested on its own.&lt;/li&gt;
&lt;li&gt;Jobs are tested separately with inline Sidekiq workers.&lt;/li&gt;
&lt;li&gt;Because logic is separated, we can:&lt;/li&gt;
&lt;li&gt;Mock external API calls in services&lt;/li&gt;
&lt;li&gt;Simulate platform failures&lt;/li&gt;
&lt;li&gt;Write isolated tests for platform behaviors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This would be a nightmare with fat models or controllers.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;br&gt;
If you’re building a Rails app that interacts with third-party APIs, handles user actions asynchronously, or needs to scale beyond a weekend project…&lt;/p&gt;

&lt;p&gt;💡 Split logic into service objects&lt;br&gt;
🧠 Run tasks with Sidekiq&lt;/p&gt;

&lt;p&gt;That combo gave us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A cleaner codebase&lt;/li&gt;
&lt;li&gt;Faster iteration cycles&lt;/li&gt;
&lt;li&gt;Fewer bugs&lt;/li&gt;
&lt;li&gt;Less stress&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rails gives you the foundation. These two patterns help you build skyscrapers on top of it.&lt;/p&gt;

&lt;p&gt;Oh, and one more thing…&lt;br&gt;
Turns out we’re not the only social media management tool built with Rails,  shoutout to &lt;a href="https://publer.com/" rel="noopener noreferrer"&gt;Publer&lt;/a&gt;, whose product and UX has definitely inspired us along the way.&lt;/p&gt;

&lt;p&gt;Rails is alive and well. And with service objects + Sidekiq, it scales beautifully.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>robinreach</category>
      <category>sidekiq</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Integrate Your SaaS with AppSumo: A Step-by-Step Guide</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Thu, 13 Mar 2025 16:23:53 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/how-to-integrate-your-saas-with-appsumo-a-step-by-step-guide-288e</link>
      <guid>https://forem.com/shahershamroukh/how-to-integrate-your-saas-with-appsumo-a-step-by-step-guide-288e</guid>
      <description>&lt;p&gt;If you're launching your SaaS on AppSumo, integrating with their API is crucial for a smooth user experience. This guide walks you through the AppSumo authentication and license verification process, using a fully working Ruby on Rails example.&lt;/p&gt;

&lt;p&gt;This article was inspired by RobinReach’s AppSumo integration. &lt;br&gt;
Check out &lt;a href="https://robinreach.com/" rel="noopener noreferrer"&gt;RobinReach&lt;/a&gt; for automated social media management! 🎯&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01yvhk5sfwhml7brruvt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01yvhk5sfwhml7brruvt.jpeg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Whether you're a founder or developer, this guide will help you integrate AppSumo seamlessly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Integrate with AppSumo?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AppSumo offers lifetime deals (LTDs) to a large number of users. &lt;br&gt;
To streamline onboarding and license verification, they provide an OpenID-based authentication system. By integrating with AppSumo's API, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify purchases and activate licenses automatically&lt;/li&gt;
&lt;li&gt;Handle license upgrades/downgrades&lt;/li&gt;
&lt;li&gt;Respond to AppSumo webhook events&lt;/li&gt;
&lt;li&gt;Improve user onboarding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Setting Up the Authentication Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first step in the integration is to set up an authentication flow that allows users to sign in via AppSumo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.1 Create an OAuth Redirect to AppSumo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;AppsumoAuthController&lt;/code&gt;, we define a method to generate the OAuth authorization URL and redirect users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AppsumoAuthController &amp;lt; ApplicationController
  skip_before_action :authenticate_user!
  skip_before_action :verify_authenticity_token

  CLIENT_ID = Rails.application.credentials.appsumo.client_id
  REDIRECT_URI = 'https://robinreach.com/appsumo/callback'

  def redirect
    auth_url = "https://appsumo.com/openid/authorize?client_id=#{CLIENT_ID}&amp;amp;response_type=code&amp;amp;redirect_uri=#{REDIRECT_URI}"
    redirect_to auth_url, allow_other_host: true
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method constructs the OAuth authorization URL, allowing users to authenticate via AppSumo. Upon successful authentication, users are redirected to the specified callback URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.2 Handle the Callback and Exchange Code for an Access Token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When users approve the authentication, AppSumo redirects them back with an authorization code. We exchange this code for an access token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def callback
  code = params[:code]
  return redirect_to auth_url if code.blank?

  response = fetch_access_token(code)
  if response['access_token']
    session[:appsumo_access_token] = response['access_token']
    session[:appsumo_refresh_token] = response['refresh_token']
    redirect_to appsumo_license_path
  else
    render json: { error: response['error'] || 'Failed to authenticate' }, status: :unauthorized
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;fetch_access_token&lt;/code&gt; method sends a request to AppSumo to retrieve the access token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fetch_access_token(code)
  response = self.class.post('/token/', headers: { 'Content-Type' =&amp;gt; 'application/json' }, body: {
    client_id: CLIENT_ID,
    client_secret: Rails.application.credentials.appsumo.client_secret,
    code: code,
    redirect_uri: REDIRECT_URI,
    grant_type: 'authorization_code'
  }.to_json)

  response.parsed_response
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step is essential for securely retrieving an access token, which will be used for further API requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Fetch and Validate the License Key&lt;/strong&gt;&lt;br&gt;
Once authenticated, we need to fetch the license key to check if the user has a valid AppSumo purchase&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def fetch_license
  access_token = session[:appsumo_access_token]
  if access_token
    response = self.class.get("/license_key/", query: { access_token: access_token })
    if response.success?
      license_key = response.parsed_response["license_key"]
      handle_license_verification(license_key)
    else
      refresh_access_token
    end
  else
    redirect_to new_user_session_path
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method retrieves the license key and checks if it belongs to an existing Company. If not, the user is directed to sign up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Handling Webhook Events&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AppSumo sends webhooks for key events like purchases, upgrades, and deactivations. We need to process them accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def webhook
  payload = JSON.parse(request.body.read)
  license_key = payload['license_key']
  event = payload['event']
  tier = payload['tier'].to_i

  case event
  when 'activate', 'purchase'
    REDIS.set(license_key, { license_key: license_key, tier: tier }.to_json, ex: 60 * 60 * 24 * 60)
    render json: { success: true, event: event }, status: :ok
  when 'upgrade', 'downgrade'
    update_license(license_key, payload['prev_license_key'], tier)
  when 'deactivate'
    deactivate_license(license_key)
  else
    render json: { success: false, error: 'Unknown event' }, status: :bad_request
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Store in Redis?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We use Redis to temporarily store the license data for quick access. This reduces the number of database queries and speeds up license verification. The data is set to expire after 60 days, ensuring that stale licenses are not kept indefinitely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updating the Company Based on the Event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For events like purchases or upgrades, we update the Company record to reflect the new subscription tier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def update_company_license(license_key, tier)
  company = Company.find_by(license_key: license_key)
  if company
    company.update(plan_tier: tier)
  else
    Company.create(license_key: license_key, plan_tier: tier)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that companies have the correct access level based on their AppSumo purchase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Securing Webhooks with Signature Verification&lt;/strong&gt;&lt;br&gt;
Since webhooks can be exploited, we verify requests using HMAC-SHA256 signatures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def verify_signature
  timestamp = request.headers['X-Appsumo-Timestamp']
  signature = request.headers['X-Appsumo-Signature']
  body = request.raw_post

  return render json: { success: false, error: 'Missing headers' }, status: :unauthorized unless timestamp &amp;amp;&amp;amp; signature &amp;amp;&amp;amp; body

  message = "#{timestamp}#{body}"
  calculated_signature = OpenSSL::HMAC.hexdigest('SHA256', API_KEY, message)

  unless ActiveSupport::SecurityUtils.secure_compare(signature, calculated_signature)
    render json: { success: false, error: 'Invalid signature' }, status: :unauthorized
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents unauthorized requests and protects your system from fraudulent webhooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integrating AppSumo’s API into your SaaS can automate user onboarding, license management etc.&lt;/p&gt;

&lt;p&gt;Key Takeaways:&lt;/p&gt;

&lt;p&gt;✅ Implement OAuth authentication for AppSumo users&lt;br&gt;
✅ Retrieve and validate AppSumo license keys&lt;br&gt;
✅ Handle webhook events for upgrades, downgrades, and deactivations&lt;br&gt;
✅ Secure webhooks using signature verification&lt;/p&gt;

&lt;p&gt;This integration ensures that your SaaS can handle AppSumo deals efficiently while providing a seamless experience to users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test OAuth flow and webhook processing.&lt;/li&gt;
&lt;li&gt;Monitor webhook logs for debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more details, refer to the AppSumo Licensing &lt;a href="https://docs.licensing.appsumo.com/#overview" rel="noopener noreferrer"&gt;Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This guide is inspired by RobinReach’s integration with AppSumo. Discover how RobinReach simplifies social media management with automation and smart scheduling! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Just Launched RobinReach: Multi-Channel Social Media Management 🚀</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Wed, 18 Dec 2024 09:40:19 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/just-launched-robinreach-multi-channel-social-media-management-pc1</link>
      <guid>https://forem.com/shahershamroukh/just-launched-robinreach-multi-channel-social-media-management-pc1</guid>
      <description>&lt;p&gt;Hey Everyone! 👋&lt;/p&gt;

&lt;p&gt;I’m excited to share that RobinReach, my social media management platform, is now live on &lt;a href="https://www.producthunt.com/posts/robinreach" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;! 🎉&lt;/p&gt;

&lt;p&gt;RobinReach is built with Ruby on Rails and designed for small businesses, teams, and agencies to simplify their social media workflows.&lt;/p&gt;

&lt;p&gt;Here’s what makes it stand out:&lt;/p&gt;

&lt;p&gt;🌍 Multi-channel support: Manage all your social media accounts (Instagram, LinkedIn, Facebook, Twitter, and more) in one place.&lt;/p&gt;

&lt;p&gt;✍️ Content creation: AI-assisted tools for generating and optimizing posts.&lt;/p&gt;

&lt;p&gt;🔁 Content repurposing: Easily reuse and adapt content for different platforms to maximize reach.&lt;/p&gt;

&lt;p&gt;📊 Analytics: Actionable insights to measure performance and improve engagement.&lt;/p&gt;

&lt;p&gt;Whether you're scheduling posts, repurposing old content, or reviewing metrics, RobinReach aims to save time and boost results.&lt;/p&gt;

&lt;p&gt;💡 Built primarily with Ruby on Rails, integrated with ChatGPT, FFmpeg, and Unsplash. It also supports features like TikTok/YouTube Shorts video generation and Canva image editing.&lt;/p&gt;

&lt;p&gt;👉 Check it out here: &lt;a href="https://www.producthunt.com/posts/robinreach" rel="noopener noreferrer"&gt;RobinReach on Product Hunt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Would love to hear your thoughts on:&lt;br&gt;
1️⃣ The concept—does it fill a gap you see in social media management?&lt;br&gt;
2️⃣ The tech side—any feedback or tips on scaling multi-channel management features?&lt;br&gt;
3️⃣ Advice on making the most of a PH launch if you've done one before!&lt;/p&gt;

&lt;p&gt;Let’s chat—I'm happy to answer questions about the tech stack, challenges, or lessons learned. 🚀&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>automation</category>
      <category>ruby</category>
      <category>ai</category>
    </item>
    <item>
      <title>ActiveRecord Calculations</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Tue, 29 Mar 2022 16:40:24 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/activerecord-calculations-3fd0</link>
      <guid>https://forem.com/shahershamroukh/activerecord-calculations-3fd0</guid>
      <description>&lt;p&gt;Let's talk about some useful methods that are very handy when we need to do some calculations to our database records.&lt;/p&gt;

&lt;h4&gt;
  
  
  So what is activerecord calculations?
&lt;/h4&gt;

&lt;h5&gt;
  
  
  ActiveRecord Calculations provide methods for calculating values of columns in the ActiveRecord models.
&lt;/h5&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;count&lt;/code&gt; Method
&lt;/h3&gt;

&lt;p&gt;Let's start with a method that is widely knowing for simple count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.count 
#returns the number of users.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that count is not always the most performant with that being said &lt;br&gt;
this &lt;a href="https://longliveruby.com/articles/active-record-counting-records"&gt;article&lt;/a&gt; demonstrates the difference between &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;length&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;count&lt;/code&gt; has much more to offer 🔥 so let's see the different usage of count below 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.count(:address)
# returns the count of all users whose address exist in our db.
&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;User.distinct.count(:city)
# returns the count of different cities we have in our db.
&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;User.group(:city).count
# returns a hash with each city and it's count.
#{ 'Cairo' =&amp;gt; 5, 'Qina' =&amp;gt; 3 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also do the above 👆 with multiple columns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Post.group(:status, :category).count
# {["draft", "business"]=&amp;gt;10, ["published", "art"]=&amp;gt;5}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;maximum&lt;/code&gt; Method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.maximum(:age)
# 98
# returns the maximum value on the given column.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;minimum&lt;/code&gt; Method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.minimum(:age)
# 18
# returns the minimum value on the given column.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;average&lt;/code&gt; Method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.average(:age)
# 27.5
# returns the average value on the given column.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;sum&lt;/code&gt; Method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.sum(:age)
# 7845
# returns the sum of the values on the given column.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;ids&lt;/code&gt; Method
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.ids
# returns the users ids
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Please check out &lt;a href="https://api.rubyonrails.org/v7.0.2.3/classes/ActiveRecord/Calculations.html"&gt;the documentation&lt;/a&gt; for reference.&lt;/p&gt;

&lt;p&gt;I hope you found the article useful and enjoyed reading as much as i enjoyed writing it 😃.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Ruby Sets</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Tue, 15 Feb 2022 20:06:25 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/ruby-sets-1b55</link>
      <guid>https://forem.com/shahershamroukh/ruby-sets-1b55</guid>
      <description>&lt;h2&gt;
  
  
  What is a Ruby Set
&lt;/h2&gt;

&lt;p&gt;Ruby Set is a class implementing the mathematical concept of &lt;a href="https://en.wikipedia.org/wiki/Set_(mathematics)"&gt;Set&lt;/a&gt;.&lt;br&gt;
Meaning it stores items like an array without duplicate items  so all the items in a set are guaranteed to be unique and it is a lot more faster and has some special capabilities.&lt;/p&gt;

&lt;p&gt;Before getting into how to use set class let's first determine when do we use it.&lt;/p&gt;
&lt;h3&gt;
  
  
  When to use sets
&lt;/h3&gt;

&lt;p&gt;Here are the few cases where sets work better:-&lt;br&gt;
1- Elements order does not matter.&lt;br&gt;
2- No duplicate values allowed.&lt;br&gt;
3- The sequences needs to be compared for equality regardless of the order.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to use sets
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt; require 'set'
&amp;gt;&amp;gt; fruits = Set.new
&amp;gt;&amp;gt; fruits &amp;lt;&amp;lt; "Apple"
&amp;gt;&amp;gt; fruits.add("Orange")
&amp;gt;&amp;gt; fruits
=&amp;gt; #&amp;lt;Set: {"Apple", "Orange"}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can also do this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;&amp;gt; numbers = Set[1, 2, 3, 4]
=&amp;gt; #&amp;lt;Set: {1, 2, 3, 4}&amp;gt;
Notice no duplicates allowed:
&amp;gt;&amp;gt; numbers &amp;lt;&amp;lt; 3
=&amp;gt; #&amp;lt;Set: {1, 2, 3, 4}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Here are some useful methods to use with sets
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include?
&amp;gt;&amp;gt; numbers.include?(4)
=&amp;gt; true

#delete
&amp;gt;&amp;gt; numbers.delete(2)
=&amp;gt; #&amp;lt;Set: {1, 3, 4}&amp;gt;

#disjoint?
&amp;gt;&amp;gt; numbers
=&amp;gt; #&amp;lt;Set: {1, 3, 4}&amp;gt;
&amp;gt;&amp;gt; numbers.disjoint? Set[5, 6]
=&amp;gt; true      #No elements in common the opposite is intersect?

#union or |
&amp;gt;&amp;gt; numbers
=&amp;gt; #&amp;lt;Set: {1, 3, 4}&amp;gt;
&amp;gt;&amp;gt; numbers.union Set[2, 4, 5] 
=&amp;gt; #&amp;lt;Set: {1, 3, 4, 2, 5}&amp;gt;
&amp;gt;&amp;gt; numbers | Set[2, 4, 5] 
=&amp;gt; #&amp;lt;Set: {1, 3, 4, 2, 5}&amp;gt;

#delete_if &amp;amp; It's opposite keep_if
&amp;gt;&amp;gt; fruits
=&amp;gt; #&amp;lt;Set: {"Apple", "Orange", "melon"}&amp;gt;
&amp;gt;&amp;gt; fruits.delete_if { |f| f == "melon"}
=&amp;gt; #&amp;lt;Set: {"Apple", "Orange"}&amp;gt;

#clear
&amp;gt;&amp;gt; numbers.clear
=&amp;gt; #&amp;lt;Set: {}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As well as the method above Set is easy to use with Enumerable objects.&lt;/p&gt;

&lt;p&gt;For more details please check out &lt;a href="https://ruby-doc.org/stdlib-2.7.1/libdoc/set/rdoc/Set.html"&gt;ruby-doc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we know how to use ruby sets for better performance and easier coding.&lt;br&gt;
So if you are using Ruby in your current project and you think that any of the cases above apply to you, you should consider using ruby sets.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading the article as i enjoyed writing it if so Please share it so more people can find it 🙂&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>sets</category>
      <category>rubysets</category>
    </item>
    <item>
      <title>Working With Folders &amp; Files In Ruby</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Fri, 08 Oct 2021 20:05:27 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/working-with-folders-files-in-ruby-2l97</link>
      <guid>https://forem.com/shahershamroukh/working-with-folders-files-in-ruby-2l97</guid>
      <description>&lt;h2&gt;
  
  
  How to work with folders and files in ruby?
&lt;/h2&gt;

&lt;p&gt;Ruby has two built in classes for us to work with files and folders those classes are &lt;code&gt;Dir&lt;/code&gt; for directories and &lt;code&gt;File&lt;/code&gt; for the files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby &lt;code&gt;Dir&lt;/code&gt; class.
&lt;/h3&gt;

&lt;p&gt;To create a Dir instance, you pass a directory path to new like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;d = Dir.new("/home/shaher/work/test")
d.entries
=&amp;gt; ["..", ".", "file.txt", "main.rb", ".csv"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also use the class method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dir.entries("/home/shaher/work/test")
=&amp;gt; ["..", ".", "file.txt", "main.rb", ".csv"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can get hold of the entries using the entries method,&lt;br&gt;
or using the glob technique. &lt;br&gt;
And the main difference is that globbing the directory doesn’t return the hidden entries (entries whose names start with a period.)&lt;br&gt;
It also permits the  wildcard matching and the recursive matching in the subdirectories.&lt;/p&gt;

&lt;p&gt;Now with &lt;code&gt;entries&lt;/code&gt; method we have the files in a nicely structured array so let's dive into the file class to do the work on our files.&lt;/p&gt;
&lt;h3&gt;
  
  
  Ruby &lt;code&gt;File&lt;/code&gt; class
&lt;/h3&gt;

&lt;p&gt;To create the file and write value we can do the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f = File.new("comment.txt", "w")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you will see the file created and we have the object to use.&lt;br&gt;
Let's add some text to the file we just created and close the file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f.puts "this text meant to be added to the comment file"
f.close
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;well we added the text but we wanna add more and update the file then we do the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f = File.new("comment.txt", "a")
f.puts "we added this extra text to update the file"
f.close
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have our file holds the text we added and updated.&lt;/p&gt;

&lt;p&gt;But using &lt;code&gt;File.new&lt;/code&gt; to create a File object make us close the file ourselves.&lt;br&gt;
Ruby as always being elegant and meant for our happiness it  provides an alternate way to open files that puts&lt;br&gt;
the task of closing the file in it's hands.&lt;br&gt;
&lt;code&gt;File.open&lt;/code&gt; with a code block.&lt;/p&gt;

&lt;p&gt;When we call File.open with a block, the block receives the File object as its single argument.&lt;br&gt;
So we use that File object inside the block and When the block ends, the File object is automatically closed.&lt;/p&gt;

&lt;p&gt;In the following example our file is opened and read in line by line for processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;File.open("comment.txt") do |f|
  f.each do |line|
    puts line.upcase
  end
end
=&amp;gt; THIS TEXT MEANT TO BE ADDED TO THE COMMENT FILE
=&amp;gt; WE ADDED THIS EXTRA TEXT TO UPDATE THE FILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ruby stops iterating when it hits the end of the file and closes the file.&lt;/p&gt;

&lt;p&gt;Another method ruby provides is &lt;code&gt;readlines&lt;/code&gt; which reads the whole file into an array like the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;File.readlines("comment.txt") do |f| 
  f.each do |line| 
    puts line
  end
end
=&amp;gt; ["this text meant to be added to the comment file\n", "we added this extra text to update the file\n"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But why all that and  not just iterate on the file and avoid wasting the space required to hold the file’s contents in memory?&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Along with File and Dir classes there is also FileUtils module which provides some practical and convenient methods that make it easy to manipulate files from Ruby in a concise manner and in ways that correspond to familiar system commands.&lt;br&gt;
&lt;a href="https://ruby-doc.org/core-2.5.0/File.html"&gt;File class reference&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ruby-doc.org/core-2.5.0/Dir.html"&gt;Dir class reference&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading this article and found it useful! 🙂&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Ruby Regular Expressions</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Mon, 04 Oct 2021 18:18:47 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/ruby-regular-expressions-5d0p</link>
      <guid>https://forem.com/shahershamroukh/ruby-regular-expressions-5d0p</guid>
      <description>&lt;h2&gt;
  
  
  What is Ruby regular expressions (ruby regex)?
&lt;/h2&gt;

&lt;p&gt;Regular expressions appear in many programming languages, with minor differences.&lt;/p&gt;

&lt;p&gt;Their purpose is to specify character patterns that subsequently are determined to match or not match. &lt;br&gt;
Pattern matching, in turn, serves as the basis for operations like parsing log files, testing keyboard input for validity, etc.&lt;/p&gt;

&lt;p&gt;Regular expressions have a reputation of being incredibly powerful.&lt;/p&gt;

&lt;p&gt;Regular expressions are instances of the Regexp class.&lt;br&gt;
and it's literal constructor is a pair of forward slashes:&lt;br&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
=&amp;gt; Regexp 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Between the slashes we add the specifics of the regexp.&lt;br&gt;
Now Any pattern-matching operation has two ends: a regexp and a string.&lt;br&gt;
and the simplest way to do that with the &lt;code&gt;match&lt;/code&gt; method.&lt;br&gt;
we can do this either way since regular-expression&lt;br&gt;
objects and string objects both respond to &lt;code&gt;match&lt;/code&gt;.&lt;br&gt;
Ruby also provides pattern-matching operator,&lt;br&gt;
&lt;code&gt;=~&lt;/code&gt;(equal sign and tilde).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p "Match!" if /ruby/.match("ruby is wonderful")
=&amp;gt; "Match!"

p "Match!" if "ruby is wonderful"=~(/ruby/)
=&amp;gt; "Match!" 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building regular expression pattern
&lt;/h2&gt;

&lt;p&gt;When we write a regexp, we put the definition of the pattern between the forward slashes //.&lt;br&gt;
and what we are putting simply a set of predictions that we want to look for in a string.&lt;/p&gt;
&lt;h3&gt;
  
  
  regex components
&lt;/h3&gt;

&lt;p&gt;Literal characters,&lt;code&gt;/r/&lt;/code&gt; “match this character”.&lt;br&gt;
The dot wildcard character (.), “match any character”.&lt;br&gt;
Character classes, [aeiou] matches any vowel.&lt;/p&gt;

&lt;p&gt;So far, we’ve looked at basic match operations which are true/false tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;regex.match(string)
string.match(regex)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Till now we got the basics of regexp, and for everyone &lt;br&gt;
I definitely recommend trying out &lt;a href="https://rubular.com/" rel="noopener noreferrer"&gt;Rubular&lt;/a&gt; to build your own regexp taking advantage of it's quick reference, which is awesome for practice, and it is very interactive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5mm2c845qv96ju7s72h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5mm2c845qv96ju7s72h.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading the topic as much as i enjoyed writing it. 🙂&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Most Handy Ruby Array Methods</title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Mon, 06 Sep 2021 20:01:58 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/most-handy-ruby-array-methods-2g8g</link>
      <guid>https://forem.com/shahershamroukh/most-handy-ruby-array-methods-2g8g</guid>
      <description>&lt;h2&gt;
  
  
  The Handiest Ruby Array Methods
&lt;/h2&gt;

&lt;p&gt;Array is a fundamental class in ruby, so whether you are building a ruby program or developing a rails app, having a good knowledge of array methods will be very helpful.&lt;br&gt;
and it's a most to know some of these methods.&lt;/p&gt;

&lt;p&gt;If you want to know more about Ruby arrays, take a look at &lt;a href="https://www.ruby-lang.org/en/"&gt;Ruby-Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quick tip😉 &lt;br&gt;
You can have access to ruby docs via the terminal by running the following command &lt;code&gt;rvm docs generate&lt;/code&gt;&lt;br&gt;
then you can look up anything for example we will see the &lt;code&gt;.first&lt;/code&gt; array method so we run &lt;code&gt;ri Array#first&lt;/code&gt; also by running &lt;code&gt;ri Array&lt;/code&gt; this will output all the information about the array class and it's instance methods as well it's class methods.&lt;/p&gt;

&lt;p&gt;So without further ado let's create our array and get started.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;arr = Array(1..5)&lt;/code&gt; that's same as &lt;code&gt;arr = [1, 2, 3, 4, 5]&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  .first
&lt;/h3&gt;

&lt;p&gt;As the name implies this method gets the first element of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.first
=&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .last
&lt;/h3&gt;

&lt;p&gt;As the name implies this method gets the last element of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.last
=&amp;gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .length
&lt;/h3&gt;

&lt;p&gt;This the most common one, this method will return the number of elements in the array&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.length
=&amp;gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .take
&lt;/h3&gt;

&lt;p&gt;The method returns an array with the number of elements we pass to it as an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.take(4)
=&amp;gt; [1, 2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .drop
&lt;/h3&gt;

&lt;p&gt;The method returns an array without the number of elements we pass to it as an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.drop(4)
=&amp;gt; [5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .shift
&lt;/h3&gt;

&lt;p&gt;This will remove the first element of an array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.shift
=&amp;gt; 1

arr
=&amp;gt; [2, 3, 4, 5] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .pop
&lt;/h3&gt;

&lt;p&gt;This will remove the last element of an array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.pop
=&amp;gt; 5

arr
=&amp;gt; [2, 3, 4] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .unshift
&lt;/h3&gt;

&lt;p&gt;This will add the element to the beginning of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.unshift(1)
=&amp;gt; [1, 2, 3, 4] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .push
&lt;/h3&gt;

&lt;p&gt;This will add the element to the end of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.push(5)
=&amp;gt; [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .insert
&lt;/h3&gt;

&lt;p&gt;With this method we can add elements to the array at any position.&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, 4, 5]
arr.insert(3, nil, true, "Mango")

=&amp;gt; [1, 2, 3, nil, true, "Mango", 4, 5] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .compact
&lt;/h3&gt;

&lt;p&gt;This method will remove the nil values from the array&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [nil, 1, 2, nil, 3, 4, 5, nil]
arr.compact
=&amp;gt; [1, 2, 3, 4, 5] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  array index
&lt;/h3&gt;

&lt;p&gt;When we want to access a specific element in the array we use it's index since each element in the array has an index which starts at 0, and if the index does not exist in the array we get nil returned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr[0]
=&amp;gt; 1

arr[3]
=&amp;gt; 4

arr[-1]
=&amp;gt; 5

arr[2] = 7
arr
=&amp;gt; [1, 2, 7, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another way to access a particular array element is by using the at method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.at(0)
=&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .delete_at
&lt;/h3&gt;

&lt;p&gt;This method will remove the element based on the index we provide as an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.delete_at(0)
=&amp;gt; [2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .reverse
&lt;/h3&gt;

&lt;p&gt;This method will reverse the array items, keep in mind it will not mutate the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.reverse
=&amp;gt; [5, 4, 3, 2]

arr
=&amp;gt; [2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .include?
&lt;/h3&gt;

&lt;p&gt;This method checks if the given argument included in the array or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr.include?(5)
=&amp;gt; true

arr.include?(9)
=&amp;gt; false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .empty?
&lt;/h3&gt;

&lt;p&gt;This method checks whether an array contains any elements at all.&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, 4, 5]
arr.empty?
=&amp;gt; false

arr = []
arr.empty?
=&amp;gt; true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .concat
&lt;/h3&gt;

&lt;p&gt;The concat method takes multiple arrays as an argument and returns one array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [0, 1, 2, 3]
arr.concat([4, 5, 6, 7], Array(8..10))

=&amp;gt; [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  .uniq
&lt;/h3&gt;

&lt;p&gt;This method returns the unique elements in a given array and remove the duplicate ones&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, 2, 2, 3, 4, 4, 5]
arr.uniq

=&amp;gt; [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now on top of those methods the Array class include the Enumerable module, as stated in the ruby API The Enumerable mixin provides collection classes with several traversal and searching methods.&lt;/p&gt;

&lt;p&gt;Please checkout the &lt;a href="https://ruby-doc.org/core-3.0.2/Enumerable.html"&gt;Ruby-Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the reading as i have enjoyed writing it😄😄😄&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rubymethods</category>
      <category>arraymethods</category>
    </item>
    <item>
      <title>Top 5 Tips to Boost your rails app performance </title>
      <dc:creator>Shaher Shamroukh</dc:creator>
      <pubDate>Tue, 17 Aug 2021 13:08:56 +0000</pubDate>
      <link>https://forem.com/shahershamroukh/top-5-tips-to-boost-your-rails-app-performance-4mfj</link>
      <guid>https://forem.com/shahershamroukh/top-5-tips-to-boost-your-rails-app-performance-4mfj</guid>
      <description>&lt;p&gt;The performance of the web application is crucial and the app speed really matters, as it plays a great role of it's success.&lt;/p&gt;

&lt;p&gt;so what techniques will help us improve the performance of our application?&lt;/p&gt;

&lt;p&gt;Here we will talk about the top 5 easy techniques to boost the performance of the rails app.&lt;/p&gt;

&lt;h2&gt;
  
  
  1- Caching
&lt;/h2&gt;

&lt;p&gt;Caching caching caching &lt;/p&gt;

&lt;p&gt;Caching is crucial to significantly improve the app performance.&lt;br&gt;
To put it simply, caching means storing the results of a complex (or not so complex) computation in some storage and later returning them right away without the need to re-compute everything. &lt;br&gt;
Also "cache" is a French word that means "to hide" and "cache-cache" is a hide-and-seek game.&lt;/p&gt;

&lt;p&gt;Now caching is a long topic to cover in one article so i will list the resources that cover everything you need to know about rails caching.&lt;/p&gt;

&lt;p&gt;Caching with Rails: An Overview &lt;a href="https://guides.rubyonrails.org/caching_with_rails.html"&gt;rails guides&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything You Ever Wanted To Know About View Caching In Rails &lt;a href="https://www.honeybadger.io/blog/ruby-rails-view-caching/"&gt;honeybadger&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How Active-record Uses Caching To Avoid Unnecessary Trips To The Database &lt;a href="https://www.honeybadger.io/blog/rails-activerecord-caching/"&gt;honeybadger&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mastering Low Level Caching in Rails &lt;a href="https://www.honeybadger.io/blog/rails-low-level-caching/"&gt;honeybadger&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2- N+1 query problem
&lt;/h2&gt;

&lt;p&gt;This is a very popular and simple optimization technique&lt;br&gt;
but it deserves the first mention since this mistake is so prevalent.&lt;br&gt;
To eliminate the N+1 problem make use of the MySQL database joins and the Rails Active-record includes functions.&lt;/p&gt;

&lt;p&gt;Here is a good &lt;a href="https://semaphoreci.com/blog/2017/08/09/faster-rails-eliminating-n-plus-one-queries.html"&gt;article&lt;/a&gt; about eliminating the n+1 query problem and taking advantage of the bullet gem.&lt;/p&gt;

&lt;h2&gt;
  
  
  3- Use &lt;code&gt;size&lt;/code&gt; Instead of &lt;code&gt;length&lt;/code&gt; or &lt;code&gt;count&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Here is why&lt;br&gt;
&lt;code&gt;count&lt;/code&gt; will perform an SQL COUNT query&lt;br&gt;
&lt;code&gt;length&lt;/code&gt; will calculate the length of the resulting array&lt;br&gt;
&lt;code&gt;size&lt;/code&gt; will try to pick the most appropriate of the two to avoid excessive queries.&lt;br&gt;
Take a look at this &lt;a href="https://web.archive.org/web/20100210204319/http://blog.hasmanythrough.com/2008/2/27/count-length-size"&gt;article&lt;/a&gt; about size vs length vs count.&lt;/p&gt;

&lt;h2&gt;
  
  
  4- Use &lt;code&gt;pluck&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;pluck can be used to query single or multiple columns from the underlying table of a model. It accepts a list of column names as an argument and returns an array of values of the specified columns with the corresponding data type.&lt;/p&gt;

&lt;p&gt;Unlike select, pluck directly converts a database result into a Ruby Array, without constructing Active-record objects. This means better performance for a large or frequently-run query.&lt;/p&gt;

&lt;p&gt;To see the example and usage of pluck method check it out on rails &lt;a href="https://guides.rubyonrails.org/active_record_querying.html#pluck"&gt;guides&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5- Upgrade Ruby and rails
&lt;/h2&gt;

&lt;p&gt;New versions tend to bring performance improvements as well as security and new methods that often faster for their case uses.&lt;br&gt;
Here is a good &lt;a href="https://www.fastruby.io/blog/rails/upgrades/why-upgrade-your-rails-application.html"&gt;article&lt;/a&gt; about Why Is It Important to Upgrade Your Rails Application.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading the article as i have enjoyed writing it.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>performance</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
