<?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: Haider Ali</title>
    <description>The latest articles on DEV Community by Haider Ali (@alihaider907).</description>
    <link>https://dev.to/alihaider907</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%2F21372%2F89439cc5-b71c-4977-ad7b-7f70e6224880.jpg</url>
      <title>DEV Community: Haider Ali</title>
      <link>https://dev.to/alihaider907</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alihaider907"/>
    <language>en</language>
    <item>
      <title>Invite Plus Integration with GitHub</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Tue, 28 Jan 2025 22:51:41 +0000</pubDate>
      <link>https://dev.to/alihaider907/invite-plus-integration-with-github-g0e</link>
      <guid>https://dev.to/alihaider907/invite-plus-integration-with-github-g0e</guid>
      <description>&lt;p&gt;&lt;a href="https://getinviteplus.com/" rel="noopener noreferrer"&gt;InvitePlus&lt;/a&gt; integrates seamlessly with GitHub to simplify managing your organization’s repositories and teams. Using GitHub OAuth login, InvitePlus enables secure authentication to connect your GitHub account effortlessly. Once authenticated, you can invite new members to your GitHub organization with just a few clicks—no more navigating through multiple settings or manual invites! Additionally, offboarding becomes a breeze, as you can instantly remove members from your organization, ensuring data security and maintaining team hygiene. Here is step by step guide, on how you can integrate your GitHub with InvitePlus&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://getinviteplus.com" rel="noopener noreferrer"&gt;InvitePlus&lt;/a&gt; and login into your account&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Integrations&lt;/strong&gt; on the left menu&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Github&lt;/strong&gt; and it will redirect you to the GitHub login page&lt;/li&gt;
&lt;li&gt;Once you have authenticated, your GitHub card will turn green like in the below screenshot&lt;/li&gt;
&lt;li&gt;Now you can select &lt;strong&gt;Github&lt;/strong&gt; service on the &lt;strong&gt;Invite&lt;/strong&gt; page to send invites alongside other services to your newly hired&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alternatively, you can watch below video tutorial below for &lt;a href="https://getinviteplus.com/" rel="noopener noreferrer"&gt;InvitePlus&lt;/a&gt; integration with GitHub&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.loom.com/share/ae5d06c1c94e452bbb257be799780273?source=embed_watch_on_loom_cta" rel="noopener noreferrer"&gt;InvitePlus Demo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>github</category>
      <category>onboarding</category>
      <category>offboarding</category>
    </item>
    <item>
      <title>Tweet YouTube video with Google Chrome Extension</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Sun, 26 Jun 2022 14:38:04 +0000</pubDate>
      <link>https://dev.to/alihaider907/tweet-youtube-video-with-google-chrome-extension-36l5</link>
      <guid>https://dev.to/alihaider907/tweet-youtube-video-with-google-chrome-extension-36l5</guid>
      <description>&lt;p&gt;Posting a youtube video on Twitter seems a daunting task as it involve&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Downloading the Video&lt;/li&gt;
&lt;li&gt;Cropping videos to 2 minutes and 20 seconds or less.&lt;/li&gt;
&lt;li&gt;The minimum resolution for Twitter videos is 32 x 32 and the maximum resolution is 1920 x 1200 or 1200 x 1900&lt;/li&gt;
&lt;li&gt;Supported formats are MP4 and MOV on the Twitter mobile apps and, on the web, MP4 with H264 format with AAC audio&lt;/li&gt;
&lt;li&gt;The maximum file size is 512MB&lt;/li&gt;
&lt;li&gt;Upload each video individually one by one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to clippost.io Google Chrome Extension. It takes care of all of above requirements and convert full YouTube video into video tweet thread on Twitter with just a click. All you have to do it install and activate the extension.&lt;/p&gt;

&lt;p&gt;Please follow below step by step guide to install and activate Clippost Google Chrome Extension on your browser&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Extension
&lt;/h2&gt;

&lt;p&gt;Go to Google Chrome Web Store and search clippost or directly visit &lt;a href="https://chrome.google.com/webstore/detail/clippost/jnnhejfefoeenpmfimcmpkalencmogle"&gt;Clippost Extension&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Extension
&lt;/h2&gt;

&lt;p&gt;This extension require activation. Please follow below steps to activate the extension in Google Chrome browser&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="http://clippost.io"&gt;http://clippost.io&lt;/a&gt; and &lt;strong&gt;LOGIN WITH TWITTER&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to top right click your profile picture to and select &lt;strong&gt;Chrome Extension&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable chrome extension (If you have already enabled it just reload your page)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to use Extension
&lt;/h2&gt;

&lt;p&gt;Clippost extension provide controls to post video tweet threads. Go to any youtube video page and you will see below controls&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--27DNGDKk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/dhTHxeuXiccGjC3wRhPu7hDj8BBnyWRGTSjcNkk012ghaQ0g7QV46JM5ra_E7DayAxr_C30PzYDp-BQq16QmbYeAxg%3Dw640-h400-e365-rj-sc0x00ffffff" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--27DNGDKk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/dhTHxeuXiccGjC3wRhPu7hDj8BBnyWRGTSjcNkk012ghaQ0g7QV46JM5ra_E7DayAxr_C30PzYDp-BQq16QmbYeAxg%3Dw640-h400-e365-rj-sc0x00ffffff" alt="" width="640" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can select start and end time and click tweet icon to send tweet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Note:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;If video length is more than 2 minute and 20 seconds it will automatically convert it into video tweet thread&lt;/li&gt;
&lt;li&gt;Clippost currently only support videos which are under 1 hour duration&lt;/li&gt;
&lt;li&gt;After posting tweet via extension you can visit &lt;a href="https://clippost.io/videos"&gt;My Video&lt;/a&gt; section to check status of video (i.e. processing cropping downloading etc)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you get into any issue please do let us know at &lt;a href="mailto:info@clippost.io"&gt;info@clippost.io&lt;/a&gt;&lt;/p&gt;

</description>
      <category>youtube</category>
      <category>videotweet</category>
      <category>twitter</category>
      <category>thread</category>
    </item>
    <item>
      <title>How to Tweet YouTube video without link</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Fri, 29 Apr 2022 22:06:00 +0000</pubDate>
      <link>https://dev.to/alihaider907/how-to-tweet-youtube-video-without-link-1bjg</link>
      <guid>https://dev.to/alihaider907/how-to-tweet-youtube-video-without-link-1bjg</guid>
      <description>&lt;p&gt;&lt;a href="https://kinsta.com/blog/video-hosting/#1-youtube"&gt;YouTube is the largest video sharing website&lt;/a&gt; on the internet, by far. With 1.9 billion logged-in users active on the site every month, nothing even comes close. You can now tweet YouTube videos without link on Twitter. Video tweets get more user engagement and interaction as compared to sharing url link on Twitter. &lt;/p&gt;

&lt;p&gt;Clippost.io can convert YouTube video into video tweet. You cannot only convert clips within a YouTube video to video tweet. But, you can also post a complete thread of clips on twitter from a single YouTube video. Please follow steps below to tweet YouTube video without link.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://clippost.io"&gt;clippost.io&lt;/a&gt; and click &lt;strong&gt;LOGIN WITH TWITTER&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SSOOS5WY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ptnv544x6kmu955noab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SSOOS5WY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ptnv544x6kmu955noab.png" alt="Image description" width="880" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;

&lt;p&gt;You will see Dashboard screen after login. Click &lt;strong&gt;New Video&lt;/strong&gt; and paste your YouTube video url&lt;/p&gt;

&lt;p&gt;Note: If you want to tweet video in reply to another tweet then click on checkbox &lt;em&gt;&lt;strong&gt;Send as a reply to a tweet&lt;/strong&gt;&lt;/em&gt; and paste url of the tweet you want to reply to&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--331UaK9m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_2-2048x1184.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--331UaK9m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_2-2048x1184.png" alt="Image description" width="880" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;p&gt;It will take you to New Video screen. Now click on &lt;strong&gt;add clip&lt;/strong&gt; and add start time and end time of clip in MM:SS format where MM is minutes and SS is second.&lt;/p&gt;

&lt;p&gt;Note: If you want to tweet whole video as video tweet thread. Please select &lt;em&gt;&lt;strong&gt;Generate clips automatically&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bu5SQq-j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_3-1536x888.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bu5SQq-j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_3-1536x888.png" alt="Image description" width="880" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4
&lt;/h2&gt;

&lt;p&gt;It will take you to &lt;strong&gt;Tweet Text&lt;/strong&gt; page. In this page you can add tweet text to each clip. Also, you can choose between you want to schedule the tweet or send it immediately&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o9wJcQ70--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_5-2048x1186.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o9wJcQ70--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_5-2048x1186.png" alt="Image description" width="880" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5
&lt;/h2&gt;

&lt;p&gt;You are done&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DepTfOqK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_7-2048x1184.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DepTfOqK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_7-2048x1184.png" alt="Image description" width="880" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can keep track of status any time visiting info screen&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ypJ3n0IB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_8-2048x1187.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ypJ3n0IB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.clippost.io/wp-content/uploads/2022/04/youtube_8-2048x1187.png" alt="Image description" width="880" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also watch our YouTube video for &lt;a href="https://www.youtube.com/watch?v=5TSRIqKrZ_w&amp;amp;ab_channel=clippost"&gt;How to Tweet YouTube Video without link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For queries please email us at &lt;a href="mailto:help@clippost.io"&gt;help@clippost.io&lt;/a&gt;&lt;/p&gt;

</description>
      <category>youtube</category>
      <category>videotweet</category>
      <category>clippost</category>
    </item>
    <item>
      <title>Exploiting abstraction while writing rails controllers</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Fri, 07 May 2021 01:58:46 +0000</pubDate>
      <link>https://dev.to/alihaider907/exploiting-abstraction-while-writing-rails-controllers-48o0</link>
      <guid>https://dev.to/alihaider907/exploiting-abstraction-while-writing-rails-controllers-48o0</guid>
      <description>&lt;p&gt;&lt;a href="http://haidrali.com/wp-content/uploads/2021/05/abstract-painting3.jpeg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fhaidrali.com%2Fwp-content%2Fuploads%2F2021%2F05%2Fabstract-painting3.jpeg" alt="abstract-painting3"&gt;&lt;/a&gt;&lt;strong&gt;&lt;em&gt;Abstraction is simple and beautiful while writing abstract code is an art.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;While writing web apps apart from writing business logic most of the time we end up writing &lt;strong&gt;CRUD&lt;/strong&gt; operations (Create, Read, Update Delete). There are a bunch of methods available to generate boilerplate code i.e. scaffolding, custom generators, etc. which have their own dos and don'ts.&lt;/p&gt;

&lt;p&gt;I personally have been exploiting abstraction to write CRUD operations. Consider an example of developing a school management system where we have controllers like Student, Course, Section, Teacher, Exam, and many others. A typical student controller CRUD would be&lt;/p&gt;

&lt;pre&gt;class StudentsController &amp;lt; ApplicationController
  before_action :set_student, only: %i[ show edit update destroy ]

  def index
    @students = Student.all
  end

  def show
  end

  def new
    &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt; = Student.new
  end

  def edit
  end

  def create
    &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt; = Student.new(student_params)

    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;.save
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;, notice: "Student was successfully created." }
        format.json { render :show, status: :created, location: &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt; }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;.update(student_params)
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;, notice: "Student was successfully updated." }
        format.json { render :show, status: :ok, location: &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt; }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;.destroy
    respond_to do |format|
      format.html { redirect_to students_url, notice: "Student was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    def set_student
      &lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt; = Student.find(params[:id])
    end

    def student_params
      params.require(:student).permit(:first_name, :last_name, :roll_no, :date_of_birth)
    end
end
&lt;/pre&gt;

&lt;p&gt;Sections controller CRUD would look like&lt;/p&gt;

&lt;pre&gt;class SectionsController &amp;lt; ApplicationController
  before_action :set_section, only: %i[ show edit update destroy ]

  def index
    @sections = Section.all
  end

  def show
  end

  def new
    &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt; = Section.new
  end

  def edit
  end

  def create
    &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt; = Section.new(section_params)

    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;.save
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;, notice: "Section was successfully created." }
        format.json { render :show, status: :created, location: &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt; }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;.update(section_params)
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;, notice: "Section was successfully updated." }
        format.json { render :show, status: :ok, location: &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt; }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt;.destroy
    respond_to do |format|
      format.html { redirect_to sections_url, notice: "Section was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    def set_section
      &lt;a class="mentioned-user" href="https://dev.to/section"&gt;@section&lt;/a&gt; = Section.find(params[:id])
    end

    def section_params
      params.require(:section).permit(:name)
    end
end
&lt;/pre&gt;

&lt;p&gt;And Course CRUD would be&lt;/p&gt;

&lt;pre&gt;class CoursesController &amp;lt; ApplicationController
  before_action :set_course, only: %i[ show edit update destroy ]

  def index
    &lt;a class="mentioned-user" href="https://dev.to/courses"&gt;@courses&lt;/a&gt; = Course.all
  end

  def show
  end

  def new
    &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt; = Course.new
  end

  def edit
  end

  def create
    &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt; = Course.new(course_params)

    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;.save
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;, notice: "Course was successfully created." }
        format.json { render :show, status: :created, location: &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt; }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;.update(course_params)
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;, notice: "Course was successfully updated." }
        format.json { render :show, status: :ok, location: &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt; }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;.destroy
    respond_to do |format|
      format.html { redirect_to courses_url, notice: "Course was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    def set_course
      &lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt; = Course.find(params[:id])
    end

    def course_params
      params.require(:course).permit(:title, :credit_hours, :code, :year)
    end
end
&lt;/pre&gt;

&lt;p&gt;If you notice most of the time we are doing same kind of operation i.e. in the case of the show we first set the resource which could be &lt;strong&gt;Student&lt;/strong&gt;, &lt;strong&gt;Course&lt;/strong&gt;, &lt;strong&gt;Section&lt;/strong&gt;, etc. In general, we are dealing with a resource or resources everywhere in the controllers.&lt;/p&gt;

&lt;p&gt;In the Ruby on Rails world, we often talk about resources, we model every real-world object into Rails model as we did with the school management system &lt;strong&gt;Student&lt;/strong&gt;, &lt;strong&gt;Course&lt;/strong&gt;, &lt;strong&gt;Teacher&lt;/strong&gt;, &lt;strong&gt;Exam&lt;/strong&gt;. If we look at our above code we just specified resource name in reach controller for example in &lt;strong&gt;StudentsController&lt;/strong&gt; we used &lt;strong&gt;Student&lt;/strong&gt;, &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/student"&gt;@student&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;@students&lt;/strong&gt;, &lt;strong&gt;set_student&lt;/strong&gt;, or &lt;strong&gt;student_params&lt;/strong&gt; and the same is the case with &lt;strong&gt;CoursesController&lt;/strong&gt; we have used &lt;strong&gt;Course&lt;/strong&gt;, &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/course"&gt;@course&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/courses"&gt;@courses&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;set_course&lt;/strong&gt;, or &lt;strong&gt;course_params&lt;/strong&gt;, etc. In short, we are repeating the resource name in each file. We can come up with a  generic controller let say &lt;strong&gt;BaseController&lt;/strong&gt; where we perform all operations on a resource rather than student, course, section, etc. Then, we just inherit &lt;strong&gt;StudentsController&lt;/strong&gt;, &lt;strong&gt;CoursesController&lt;/strong&gt;, &lt;strong&gt;TeachersController&lt;/strong&gt;, &lt;strong&gt;ExamsController&lt;/strong&gt; from a single source of truth &lt;strong&gt;BaseController&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's start with the show function and try to write &lt;strong&gt;BaseController&lt;/strong&gt;.&lt;/p&gt;

&lt;pre&gt;class BaseController &amp;lt; ApplicationController
  before_action :set_resource, only: %i[ show ]

  def show
  end

  def set_resource
    resource ||= resource_class.find(params[:id])
    instance_variable_set("@#{resource_name}", resource)
  end

  def resource_class
    @resource_class ||= resource_name.classify.constantize
  end

  def resource_name
    @resource_name ||= controller_name.singularize
  end
end
&lt;/pre&gt;

&lt;p&gt;Writing create function is a bit more interesting&lt;/p&gt;

&lt;pre&gt;  def create
    &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt; = resource_class.new(resource_params)

    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;.save
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;, notice: "#{resource_name} was successfully created." }
        format.json { render :show, status: :created, location: &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt; }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end
&lt;/pre&gt;

&lt;p&gt;update and destroy functions are somewhat similar&lt;/p&gt;

&lt;pre&gt;  def update
    &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt; = resource_class.find(params[:id])

    respond_to do |format|
      if &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;.update(resource_params)
        format.html { redirect_to &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;, notice: "#{resource_name} was successfully updated." }
        format.json { render :show, status: :ok, location: &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt; }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt; = resource_class.find(params[:id])

    &lt;a class="mentioned-user" href="https://dev.to/resource"&gt;@resource&lt;/a&gt;.destroy
    respond_to do |format|
      format.html { redirect_to "#{controller_name}_url", notice: "#{resource_name} was successfully destroyed." }
      format.json { head :no_content }
    end
  end
&lt;/pre&gt;

&lt;p&gt;In all of the above rewrites, we just simply used resources as a generic variable attribute. destroying an object is the same no matter its &lt;strong&gt;Student&lt;/strong&gt;, &lt;strong&gt;Course&lt;/strong&gt;, &lt;strong&gt;Section&lt;/strong&gt;, or &lt;strong&gt;Exam&lt;/strong&gt; so resource.destroy works the same for each resource.&lt;/p&gt;

&lt;p&gt;Our final refactoring will look like this&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Since controllers are inherited from &lt;strong&gt;BaseController&lt;/strong&gt; we can always override any method in the respective controller. For example, instead of directly creating a &lt;strong&gt;Student&lt;/strong&gt; object we have a service written which takes student params and creates &lt;strong&gt;Student&lt;/strong&gt; object after applying a bunch of business logic and pre-checks. For such scenarios, we can override create the function in StudentsController.&lt;/p&gt;

&lt;p&gt;We can use the same pattern while writing our APIs and all other scenarios where we have a similar pattern repetition.&lt;/p&gt;

&lt;p&gt;Thank You so much for the read.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>ror</category>
    </item>
    <item>
      <title>AWS S3 file upload from client side</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Sat, 20 Oct 2018 22:32:06 +0000</pubDate>
      <link>https://dev.to/alihaider907/aws-s3-file-upload-from-client-side-20fp</link>
      <guid>https://dev.to/alihaider907/aws-s3-file-upload-from-client-side-20fp</guid>
      <description>&lt;p&gt;Originally posted on my personal blog &lt;a href="http://haidrali.com/aws-s3-file-upload-from-client-side/"&gt;http://haidrali.com/aws-s3-file-upload-from-client-side/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week I pushed a new feature on production which involve file upload on AWS S3. When you are uploading file to S3 from frontend there is always a risk of exposing your AWS secrets to user, so you have following options to avoid this risk&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Involve server as middleware and upload via server API, you will have more control over it&lt;/li&gt;
&lt;li&gt;Allow users to upload directly to S3 anonymously&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I don’t like both of above methods, as involving middleware you are uploading file twice i.e. frontend → server, server → s3 bucket and I don’t really want server to do this heavy lifting of uploading files to S3 on user behalf, while allowing user anonymous upload you are giving a blank check to you S3 bucket i.e. anyone in the world can upload to your s3 bucket, this was also not acceptable to me as this could have very swear consequences. I wanted to have bit more control over uploads while not compromising security issues, so I used AWS Security Token Service to generate secrets (access_key, access_secret) which lived temporarily and have limited access as you define it.&lt;/p&gt;

&lt;h3&gt;
  
  
  H3 Configure an IAM user on AWS console to generate temporary secrets
&lt;/h3&gt;

&lt;p&gt;In order to generate temporary secrets you need following configurations on AWS console&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create a new IAM user&lt;/li&gt;
&lt;li&gt;create a policy to allow upload on S3 bucket&lt;/li&gt;
&lt;li&gt;create a role for you IAM user to assume Security Token Service&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Watch this video for configurations&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/z-r5w82C8uo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now, you can generate AWS STS with this ruby code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws_sts = AWS::STS::Client.new(
          access_key_id: ENV['AWS_ACCESS_KEY_ID'],
          secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
        ).assume_role(
          role_arn: ENV['AWS_ROLE_ARN'],
          role_session_name: 'session_name',
          duration_seconds: 12*60*60)
// this will generate access_key, access_secret
aws_sts.credentials
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are credentials you download after creating user and AWS_ROLE_ARN is value which I copied at the end of video&lt;/p&gt;

&lt;h3&gt;
  
  
  H3 Enable ACL uploading to S3
&lt;/h3&gt;

&lt;p&gt;You will be able to successfully upload files with secrets generated with above code, Since we have used a separate user to generate STS then only this user will be able to access file. To make this file accessible by other user as well you must send ACL: 'public-read' in request body or header while uploading file to S3. you can read more about &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl"&gt;ACL&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this help you improve your file upload as well. If you need any help please do ping me on twitter &lt;a href="https://twitter.com/alihaider907"&gt;@alihaider907&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ruby</category>
      <category>s3</category>
      <category>security</category>
    </item>
    <item>
      <title>Newbies Introduction to Ruby on Rails</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Sat, 25 Nov 2017 13:13:48 +0000</pubDate>
      <link>https://dev.to/alihaider907/newbies-introduction-to-ruby-on-rails-4be</link>
      <guid>https://dev.to/alihaider907/newbies-introduction-to-ruby-on-rails-4be</guid>
      <description>&lt;p&gt;Originally posted on my personal blog &lt;a href="http://haidrali.com/newbies-introduction-to-ruby-on-rails"&gt;http://haidrali.com/newbies-introduction-to-ruby-on-rails&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This tutorial is intended to newbies only who want to kick-start web development with Ruby on Rails. I will just share links to different resources and give tips based on my experience which may help you starting development with Ruby on Rails.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation and Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just like any other framework ruby on rails framework has its own development environment, before diving into installations of environment I would recommend if you have  planned to use Window operating system for ruby on rails development please read &lt;a href="https://www.engineyard.com/blog/rails-development-on-windows-seriously"&gt;Rails Development on Windows&lt;/a&gt;. Seriously and switch to linux/unix based operating system. If you still insist to carry on with Windows go ahead with my Best wishes.&lt;/p&gt;

&lt;p&gt;You can find complete installation guide of Ruby on Rails on &lt;a href="https://gorails.com"&gt;GoRails&lt;/a&gt; website (there are other websites too). I will recommend installing RVM instead of rbenv and installing it from source.  &lt;a href="https://gorails.com"&gt;GoRails&lt;/a&gt; guides also include installing Git, MySQL/Postgres complete the installation process. You might get errors while installation please do check your OS and version before starting installation process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ruby Language&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you have set up your installations and environment start with ruby language basics I would recommend &lt;a href="http://www.sapphiresteel.com/IMG/pdf/LittleBookOfRuby.pdf"&gt;The Little Book of Ruby&lt;/a&gt; by &lt;em&gt;Huw Collingbourne&lt;/em&gt;. Don’t memorise anything just practice basic syntax, data structures, condition statements, loops modules and Classes. Since we have already installed ruby as well as created a project of rails (in above GoRails guide) your can either go to project root and open a console or write your program in a .rb file and run it with ruby keyword as mentioned in book.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ruby on Rails Framework&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You are familiar with Ruby language basics now it is time to start getting your hands on Ruby on Rails. You will find numerous tutorial on getting started with Rails, but &lt;a href="https://www.railstutorial.org/book/beginning"&gt;RUBY ON RAILS TUTORIAL&lt;/a&gt; by Michael Hartl is the most comprehensive guide for newbies. It covers details at granular level starting from Zero to Deployment it includes everything. There are other good resources as well like &lt;a href="http://railscasts.com/"&gt;RailsCasts&lt;/a&gt;, &lt;a href="https://www.driftingruby.com/"&gt;DriftingRuby&lt;/a&gt;, &lt;a href="https://www.railstutorial.org/"&gt;RailsTutorial&lt;/a&gt;, but if you are newbie I would highly recommend finishing Ruby on Rails Tutorial book by Micheal Hartl thoroughly first and then look elsewhere like RailsCasts (very good for topic specific tutorials) as it will make your Rails framework understanding in-depth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development Environment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Development environment contains your machine, tools, settings, configurations etc. Make your development environment as smooth as possible use .bashrc, tumx, terminal settings aliases to amplify your concentration. Have strong grip over &lt;a href="http://haidrali.com/everyday-terminal-commands-for-backend-developers/"&gt;terminal commands&lt;/a&gt;. Choose any suitable text editor I personally use Sublime Text in development and vim or emacs in production mode. Look at StackOverFlow’s survey for &lt;a href="https://insights.stackoverflow.com/survey/2017#technology-most-popular-developer-environments-by-occupation"&gt;Most Popular Developer Environments by Occupation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be Open Source&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ruby on Rails is an open source framework and it has very large open source community, as a beginner you will get lots of help from open source community in term of different gems, git, gist, stack overflow etc. Don’t forget to contribute back once you have a good grip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow Tech Talks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ruby and Ruby on Rails framework has large community of developers across the world. There are many conferences being held across the world on Ruby language and Ruby on Rails framework both. RubyConf and RailsConf are two of the most popular conferences in Ruby on Rails world. Do follow tech talks in these conferences particularly from speakers &lt;a href="https://twitter.com/dhh"&gt;David Heinemeier&lt;/a&gt;, &lt;a href="https://twitter.com/sgrif"&gt;Sean Griffin&lt;/a&gt;, &lt;a href="https://twitter.com/mperham"&gt;Mike Perham&lt;/a&gt;, &lt;a href="https://twitter.com/tenderlove"&gt;Aaron Patterson&lt;/a&gt; and people who are at the forefront of Ruby language and Ruby on Rails framework development. Look at &lt;a href="https://www.bacancytechnology.com/blog/11-top-ruby-on-rails-conferences-2017"&gt;11 TOP INTERNATIONAL RUBY ON RAILS CONFERENCES AND EVENTS 2017&lt;/a&gt;. Also one particularly article I really like every Rails developer to read is &lt;a href="http://rubyonrails.org/doctrine/"&gt;The Rails Doctrine&lt;/a&gt; by DHH.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never Stop Learning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you have develop basics of ruby on rails I would recommend having some DevOps and Front end frameworks like ReactJS, VueJS  skills as well. Do explore topics like High Availability, Consistency, Scaling RDBS, NoSQL etc and  regularly read engineering blogs of tech giants like Google, Twitter, Microsoft and Amazon etc.&lt;/p&gt;

&lt;p&gt;If you are newbie to Ruby on Rails development and want any suggestions or help do ping me on twitter &lt;a href="https://twitter.com/alihaider907"&gt;@alihaider907&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy Learning 😛&lt;/p&gt;

</description>
      <category>programming</category>
      <category>rails</category>
      <category>ruby</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How pair programming helped me focus more</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Tue, 01 Aug 2017 09:22:36 +0000</pubDate>
      <link>https://dev.to/alihaider907/how-pair-programming-helped-me-focus-more</link>
      <guid>https://dev.to/alihaider907/how-pair-programming-helped-me-focus-more</guid>
      <description>&lt;p&gt;Originally posted on my personal blog &lt;a href="http://haidrali.com/how-pair-programming-helped-me-focus-more/"&gt;http://haidrali.com/how-pair-programming-helped-me-focus-more/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am a big advocate of pair programming as I always feel more productive doing tasks in a pair because it tends to be a Get Things Done kind of attitude. Followings are reasons why I believe pair programming can help you more productive at certain stages&lt;/p&gt;

&lt;p&gt;1- The purpose of two programmers sitting on a single workstation is not always to get output greater than output of both individuals but to get the critical work done i.e, setting up your first deployment environment, debugging a rare and critical bug, code merge or code reviews etc&lt;/p&gt;

&lt;p&gt;2- If pair consists of a senior developer with a junior developer the follow of knowledge from senior to junior developer really help junior developer to learn. This is what I have experienced while working almost a year with Waqas Farooq he be a Geek and I as new-grad&lt;/p&gt;

&lt;p&gt;3- Many a time I have experienced that Unforced Errors like unintentionally making changes to another file, environment variables not loading in production are greatly reduced when a pair sit-down on a single workstation&lt;/p&gt;

&lt;p&gt;4- Almost everyone uses social media be it Facebook, Twitter, Reddit, Hacker News etc during work to get some comfort and once your dive into it then it become difficult to get out of this comfort zone. But when you sit together with your fellow programmer the follow of work never stop and social media and other hurdles never come in your way you just keep going until you hit the finish line.&lt;/p&gt;

&lt;p&gt;5- Concept of pair programming gets redefined under remote working environment as you are no longer sitting together physically but still you can be on a single workstation by the means of online realtime collaboration tools i.e. screen sharing&lt;/p&gt;

&lt;p&gt;I hope my experience would help promoting pair programming culture at your workplace.&lt;/p&gt;

&lt;p&gt;Happy Pair Programming :)&lt;/p&gt;

</description>
      <category>culture</category>
      <category>debugging</category>
      <category>deployment</category>
      <category>programming</category>
    </item>
    <item>
      <title>Data security in multi-tenant SaaS applications</title>
      <dc:creator>Haider Ali</dc:creator>
      <pubDate>Thu, 08 Jun 2017 23:11:53 +0000</pubDate>
      <link>https://dev.to/alihaider907/data-security-in-multi-tenant-saas-applications-a3c8</link>
      <guid>https://dev.to/alihaider907/data-security-in-multi-tenant-saas-applications-a3c8</guid>
      <description>&lt;p&gt;Data is the core of SaaS and having shipped two SaaS products on production in last four years I feel developing SaaS application requires extra safety measures on data security as compared to developing a general purpose application such as Chatting apps, client based solution, etc. Since in SaaS application resources are shared among clients so data security in term of data leakage between clients is a real challenge, In this post I would explain how proper measures should be taken to make sure data security in SaaS application.&lt;/p&gt;

&lt;p&gt;Choosing what database structure you will go with is important question and it should be decided after carefully going through you requirements like what type of clients you will have enterprise/small business, how large your application is, etc. because database structure in SaaS application impact directly to the security as well performance issues. Normally you have three choices to structure your database for SaaS&lt;/p&gt;

&lt;p&gt;1- Single Tenant (Each client will have a physically different database)&lt;/p&gt;

&lt;p&gt;2- Multi-Tenant (Single database for all the clients where each client data is shared)&lt;/p&gt;

&lt;p&gt;3- Multi-Tenant with multi-schema (Single database for all clients, but each client will have a separate, but homogeneous schema structure in the single database)&lt;/p&gt;

&lt;p&gt;Single Tenant for each client gives you perfect solution to data security as data of each client is physically separated, but it is not cost efficient solution as each client has to pay cost of a fully managed database, also at application level you have to maintain connections to each client’s database separately and managing backups across all tenants is a real deal. It could be a good choice where you have Banks or enterprise level clients demanding their data to be separated on physically different server.&lt;/p&gt;

&lt;p&gt;I was in huge favour of Multi-Tenant with multiple schema when I was developing SaaS, because it offers you same kind of data transparency among tenants as Single Tenant on a single database and it is cost efficient solution, but there were four things I didn’t choose Multi-Tenant with multiple schema and those were&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Our application has more then 60 tables so having N client means database will have n*60 tables and sooner or later this limit will eventually reach the maximum number of tables in a database&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Managing backups would have been a real deal at production&lt;br&gt;
It becomes difficult to maintain homogeneous schema structure as your application grow broken migration cause huge pain (I have practically experience these bugs on production)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Practically you have to switch schema with each request you make to Database&lt;br&gt;
So Multi-Tenant with multiple schema is not a good choice for an application where you have large number of tables and large number of clients, still I would recommend it if you have small number of tables in your application and measured number of clients and data security is your priority.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multi-Tenant isn’t good fit if data security is your main concern at first look since data of all clients will be shared, but you can take safety measures at your application level to make use of this cost effective and easy to manage solution. Since all clients are using same database same schema and same tables so making sure that each client can access, update and delete only its own data become high priority challenge, As many a time you are playing directly with incoming parameters which can be manipulated easily to mitigate records of other clients/tenants if not ensured properly. There are two widely known approaches to correctly identifying the tenant against each HTTP request&lt;/p&gt;

&lt;p&gt;1- Sub-domain many SaaS application use sub-domain feature like if your application is hosted at &lt;a href="http://www.application.com"&gt;www.application.com&lt;/a&gt; then client named client1 will have client1.application.com and you can easily have sub-domain to know which client’s HTTP request it is and go to database for this particular client only&lt;br&gt;
2- Maintain tenant in sessions&lt;/p&gt;

&lt;p&gt;After successfully identifying tenant, next challenge is to make sure you shield your database logically such as it only reduced to that tenant. At the ground level you have to add a condition in WHERE caluse every time you query to database. At first look it seems pretty straight forward but any negligence in this would expose data of one tenant to the other tenants. I would never recommend appending condition in WHERE cause manually this should be done right way either via using library such as &lt;a href="https://github.com/ErwinM/acts_as_tenant"&gt;acts_as_tenant&lt;/a&gt; or writing a function in your database class which automatically append this WHERE clause for tenant every time you query for data.&lt;/p&gt;

&lt;h2&gt;
  
  
  External Storage
&lt;/h2&gt;

&lt;p&gt;Apart from you primary database it is quite common that you have to use external storage such as Redis or even at times you depend on external services like Firebase, Amazon S3. The same above principle that each tenant can access, update and delete only its own data applies here too and there should be no way to reverse engineer and mitigate data present in these external storage and services such that it affects other tenants.&lt;/p&gt;

&lt;p&gt;Feel free to contact me at &lt;a href="http://twitter.com/alihaider907"&gt;@alihaider907&lt;/a&gt; about this article or building SaaS products.&lt;/p&gt;

&lt;p&gt;Thanks&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>multitenancy</category>
      <category>saas</category>
      <category>security</category>
    </item>
  </channel>
</rss>
