<?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: Zain Butt</title>
    <description>The latest articles on DEV Community by Zain Butt (@zainbutt).</description>
    <link>https://dev.to/zainbutt</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%2F1241156%2F74af7da1-189d-41a3-91a0-d4ba58109750.png</url>
      <title>DEV Community: Zain Butt</title>
      <link>https://dev.to/zainbutt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zainbutt"/>
    <language>en</language>
    <item>
      <title>Preview images on upload with StimulusJS</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Sat, 24 Feb 2024 19:39:50 +0000</pubDate>
      <link>https://dev.to/zainbutt/preview-images-on-upload-with-stimulusjs-2mfh</link>
      <guid>https://dev.to/zainbutt/preview-images-on-upload-with-stimulusjs-2mfh</guid>
      <description>&lt;p&gt;In web development, providing users with a seamless experience for uploading images is crucial. One way to enhance this experience is by offering a preview of the uploaded image before submission. In this blog post, I'll walk you through how I integrated a new StimulusJS controller to achieve image upload previews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Creating and Registering the Controller File&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, let's create a new controller file for our image upload preview feature. In your StimulusJS controllers directory, create a new file, let's call it &lt;code&gt;image_upload_preview_controller.js&lt;/code&gt;. Once the file is created, ensure that it's registered with your application by importing it in your &lt;code&gt;index.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploads&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Uploads&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Adding Required Code for Image Upload Preview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inside the controller file, we'll need to add the necessary code. We'll define the required targets to manipulate: the form containing the file input and the container for the image preview.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;previewContainer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nf"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previewContainerTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Connecting HTML Form with the Controller&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, let's connect our HTML form with the controller. Add the data-controller attribute to the form element and specify the name of our controller (image-upload-preview) as the value. Also, include the data-target attribute with the targets we defined earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;data-controller=&lt;/span&gt;&lt;span class="s"&gt;"image-upload-preview"&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"change-&amp;gt;image-upload-preview#preview"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt; &lt;span class="na"&gt;accept=&lt;/span&gt;&lt;span class="s"&gt;"image/*"&lt;/span&gt; &lt;span class="na"&gt;data-image-upload-preview-target=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Image Preview"&lt;/span&gt; &lt;span class="na"&gt;data-image-upload-preview-target=&lt;/span&gt;&lt;span class="s"&gt;"previewContainer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✨ With just a few lines of code we were able to achieve this functionality. StimulusJS is very light weight and does not get in your way.&lt;/p&gt;

&lt;p&gt;🤩 By organizing functionality into controllers, StimulusJS promotes clean and maintainable code, making it easier to manage and extend our applications.&lt;/p&gt;

&lt;p&gt;👉🏻 I built this feature for my startup &lt;a href="https://devtree.app?utm_source=devto"&gt;devtree&lt;/a&gt; where devs can build their portfolios sites and get in front of tech companies without any job search.&lt;/p&gt;

&lt;p&gt;I share my journey with everyone on &lt;a href="https://twitter.com/zainnazirbutt"&gt;twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/zainnazirbutt"&gt;linkedin&lt;/a&gt;, follow to stay tuned.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ruby</category>
      <category>rails</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Biggest update for my startup</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Sat, 24 Feb 2024 19:18:35 +0000</pubDate>
      <link>https://dev.to/zainbutt/biggest-update-for-my-startup-51mc</link>
      <guid>https://dev.to/zainbutt/biggest-update-for-my-startup-51mc</guid>
      <description>&lt;p&gt;The biggest update for devTree to date 🚀 &lt;/p&gt;

&lt;p&gt;👩🏻‍💻 Devtree is open for Businesses&lt;br&gt;
If you are tired of outsourcing and paying huge placements fees or your in-house talent team is too busy sourcing talent, then devtree would be right choice. Hire one or hundreds of developers and connect directly without any middlemen. $0 PLACEMENT FEE.&lt;/p&gt;

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

&lt;p&gt;🌐 Custom Domains&lt;br&gt;
Bring your own domain for your devtree portfolio and make it more personal.&lt;/p&gt;

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

&lt;p&gt;💰 Monthly Subscription&lt;br&gt;
Don't want to spend money on a lifetime deal, no sweat, affordable monthly subscription that starts from $1 (less than netflix subscription). Access to all premium features without any limits.&lt;/p&gt;

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

&lt;p&gt;💫 Better Onboarding for developers&lt;br&gt;
When you signup, devtree would take you through all the steps you need to make your profile better to attract right opportunities.&lt;/p&gt;

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

&lt;p&gt;A lot more to come, always open to feedback and new ideas.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ruby</category>
      <category>rails</category>
      <category>startup</category>
    </item>
    <item>
      <title>An under rated skill to make a huge difference in your interviews 🤯</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Mon, 29 Jan 2024 18:12:18 +0000</pubDate>
      <link>https://dev.to/zainbutt/an-under-rated-skill-to-make-a-huge-difference-in-your-interviews-4n9e</link>
      <guid>https://dev.to/zainbutt/an-under-rated-skill-to-make-a-huge-difference-in-your-interviews-4n9e</guid>
      <description>&lt;p&gt;Talking about your self and your contributions is an underrated skill that you should work on and master.&lt;/p&gt;

&lt;p&gt;It can be a make or break moment for anyone during in an interview.&lt;/p&gt;

&lt;p&gt;Mastering technical skills won’t be enough, you need to be eloquent and concise with what you say.&lt;/p&gt;




&lt;p&gt;Here is how you can do it 👇🏻&lt;/p&gt;

&lt;p&gt;1- Take out some time to list all the work in detail ✍🏻&lt;/p&gt;

&lt;p&gt;This is not something you can just whip up using AI, you would need some focused chunk of time to come up with what you did.&lt;/p&gt;

&lt;p&gt;The best way to do it is to keep your resume updated, it will help you coming up with some content. Select the best work you did, see if you could be recall any positive feedback or shoutouts you got.&lt;/p&gt;




&lt;p&gt;2- What choices you made and why 🤔&lt;/p&gt;

&lt;p&gt;You can't just tell them what you did, you also have to be specific why exactly you did it. Did you had multiple options to weigh? what were the constraints? What other factors influenced you decision.&lt;/p&gt;




&lt;p&gt;3- What were the impact of your contributions 📈&lt;/p&gt;

&lt;p&gt;Knowing what impact your contributions had is a major boost. Present proper numbers to back it up.&lt;br&gt;
Instead of saying "increased page load speed", you can say, "improved load time of webpage from 5 seconds to under 500ms" OR&lt;br&gt;
"Improved system efficiency" to "reduced latency from x to y by doing z"&lt;/p&gt;




&lt;p&gt;4- Simplify everything 🙃&lt;/p&gt;

&lt;p&gt;Once you have all of the content, go ahead and structure it. Make it simple to understand and concise. Nobody wants to hear about a single thing for a long time just to misunderstand you.&lt;/p&gt;




&lt;p&gt;5- Talk to some people 🙏🏻&lt;/p&gt;

&lt;p&gt;Talking with some people like recruiters, colleagues or friends won't hurt and see if they were able to understand and ask them about it. Were you concise and easy to understand.&lt;/p&gt;




&lt;p&gt;I certainly had my moments of poor communication at one point and still make a mess of things but by acknowledging your short comings and aiming to improve is the only way to go ahead.&lt;/p&gt;




&lt;p&gt;Hey, i am Zain, an indiehacker helping developers land jobs without getting ghosted and search anxiety with my startup &lt;a href="https://devtree.app?utm_source=devto"&gt;devtree&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I share my technical and indiehacking learnings on &lt;a href="https://linkedin.com/in/zainnazirbutt"&gt;linkedin&lt;/a&gt; and &lt;a href="https://twitter.com/zainnazirbutt"&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>interview</category>
      <category>programming</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>What was the best moment in your dev career??</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Wed, 10 Jan 2024 17:24:08 +0000</pubDate>
      <link>https://dev.to/zainbutt/what-was-the-best-moment-in-your-dev-career-454l</link>
      <guid>https://dev.to/zainbutt/what-was-the-best-moment-in-your-dev-career-454l</guid>
      <description>&lt;p&gt;Hey fellow developers! 🚀 &lt;/p&gt;

&lt;p&gt;We're a community of extraordinary minds, each contributing to the tech world in our own unique ways. From crafting elegant lines of code to building robust systems, we've all achieved some amazing feats. &lt;/p&gt;

&lt;p&gt;Some of us have tackled complex algorithms, while others have created sleek user interfaces that redefine user experiences and maybe some have just changed border radius of a link (jk).&lt;/p&gt;

&lt;p&gt;I'm curious to hear about the moments in your career that truly pushed your limits. What's the most intricate problem you've solved, the most challenging project you've undertaken, or the feature that seemed impossible at first but you conquered?&lt;/p&gt;




&lt;p&gt;Let's share our triumphs and learn from the hurdles that shaped us. Drop your stories below and let's celebrate the brilliance that resides in our developer community!&lt;/p&gt;




&lt;p&gt;I am a indiehacker and building my startup &lt;a href="https://devtree.app?utm_source=devto"&gt;devtree&lt;/a&gt; in public and share my insights, lessons and successes along the way. &lt;/p&gt;

&lt;p&gt;You can also find me on &lt;a href="https://twitter.com/zainnazirbutt"&gt;twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/zainnazirbutt"&gt;linkedin&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Free tools for developers to build their apps</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Fri, 05 Jan 2024 16:27:03 +0000</pubDate>
      <link>https://dev.to/zainbutt/free-tools-for-developers-to-build-their-apps-412h</link>
      <guid>https://dev.to/zainbutt/free-tools-for-developers-to-build-their-apps-412h</guid>
      <description>&lt;p&gt;In the dynamic and competitive landscape of app development, startups and developers often find themselves navigating tight budgets and limited resources. Building a successful app requires a blend of creativity, dedication, and, most importantly, the right tools. In the early stages of my startup journey, I quickly realized the immense value of leveraging free resources to kickstart app development without breaking the bank.&lt;/p&gt;

&lt;p&gt;Server costs, software licenses, and development tools can quickly add up, potentially hindering the progress of a promising project. However, in today's tech-driven era, a wealth of free resources is available, offering developers a lifeline to overcome financial barriers and transform their ideas into reality.&lt;/p&gt;

&lt;p&gt;So, today I will share some free resources that developers can utilize in their projects. The tools are divided into multiple categories like API, Cloud, BugTracking etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://free-for.dev"&gt;Free resources list&lt;/a&gt; 👈🏻&lt;/p&gt;

&lt;p&gt;Go ahead and explore the free resources and it might give some ideas.&lt;/p&gt;

&lt;p&gt;Some of my favorites:&lt;/p&gt;

&lt;p&gt;1- &lt;a href="https://upstash.com/"&gt;Upstash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Serverless redis, no need to spin up your own instance. Free 10k Requests per day.&lt;/p&gt;

&lt;p&gt;2- &lt;a href="https://fly.io"&gt;fly.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fly is a platform for applications that must run globally. It runs your code close to users and scales compute in cities where your app is busiest. Write your code, package it into a Docker image, deploy it to Fly's platform, and let that do all the work to keep your app snappy. Free allowances include up to 3 shared-CPU-1x 256mb VMs, 3GB persistent volume storage (total), and 160GB outbound data transfer.&lt;/p&gt;

&lt;p&gt;3- &lt;a href="https://ipinfo.io/"&gt;IPinfo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fast, accurate, and free (up to 50k/month) IP address data API.&lt;/p&gt;

&lt;p&gt;4- &lt;a href="https://zoho.com"&gt;Zoho&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Started as an e-mail provider but now provides a suite of services, some of which have free plans. I use their email services for all my startups. Free upto 5 users.&lt;/p&gt;

&lt;p&gt;5- &lt;a href="https://configcat.com/"&gt;ConfigCat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ConfigCat is a developer-centric feature flag service with unlimited team size, excellent support, and a reasonable price tag. Free plan up to 10 flags, two environments, 1 product, and 5 Million requests per month.&lt;/p&gt;

&lt;p&gt;6- &lt;a href="https://posthog.com/"&gt;PostHog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full Product Analytics suite free for up to 1m tracked events per month.&lt;/p&gt;

&lt;p&gt;There are hundreds of these tools for you to use. Go check it out.&lt;/p&gt;




&lt;p&gt;My name is Zain and I am building &lt;a href="https://devtree.app?utm_source=devto"&gt;devtree&lt;/a&gt; where developers can get hired without any job search.&lt;/p&gt;

&lt;p&gt;I post about my journey, lessons learned and success on &lt;a href="https://twitter.com/zainnazirbutt"&gt;twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/zainnazirbutt"&gt;linkedin&lt;/a&gt;. You will also find other things on my devtree profile as well.&lt;/p&gt;

&lt;p&gt;If you want to learn about working on Startups, Rails and general life advice follow me.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>Add Custom Domains To Your Rails App</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Mon, 01 Jan 2024 16:28:39 +0000</pubDate>
      <link>https://dev.to/zainbutt/add-custom-domains-to-your-rails-app-24ip</link>
      <guid>https://dev.to/zainbutt/add-custom-domains-to-your-rails-app-24ip</guid>
      <description>&lt;p&gt;I often saw a lot of apps giving the ability to use our own domain to either access the app or personalise some part of it. For instance, if you want to map your domain/subdomain to an external blogging system Or use your own domain to generate short links.&lt;/p&gt;

&lt;p&gt;I was very curious as to how would this work, turns out its not so complicated.&lt;/p&gt;




&lt;p&gt;For this to work properly, your user will need to set their website’s custom_domain to iamzain.com in your app. With that in place, the request flow looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1- A user visits &lt;code&gt;iamzain.com&lt;/code&gt;, which points to &lt;code&gt;devtree.app&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2- Your app handles the request from the custom domain, routing the request to the &lt;code&gt;#index&lt;/code&gt; action in ProfilesController&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3- Your controller looks up the user with &lt;code&gt;iamzain.com&lt;/code&gt; as the &lt;code&gt;custom_domain&lt;/code&gt; and renders it&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These instructions are primarily targeted for Rails application but the concept could be ported to any language/framework.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;There are a few steps involved, let’s get going:&lt;/p&gt;

&lt;h3&gt;
  
  
  1- First we will make our application capable of storing the custom domain.
&lt;/h3&gt;

&lt;p&gt;Add a migration to add a column to users table&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddCustomDomainToUsers&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;
    &lt;span class="n"&gt;add_column&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:custom_domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Create a simple form for users to add custom domain and save it against the user.&lt;/p&gt;




&lt;h3&gt;
  
  
  2- Once the custom domain is saved, present the user with some CNAME records that they can add to their DNS.
&lt;/h3&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%2Fgj8pdgbggs13krw2czf9.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%2Fgj8pdgbggs13krw2czf9.png" alt="records"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how it will work, when the user adds these records to their domain DNS, it will inform the internet to forward any request to our app whenever someone types their custom domain in the browser.&lt;/p&gt;

&lt;p&gt;CNAME (canonical name) records helps us with this, rather than redirecting the users it would just forward the request to our app.&lt;/p&gt;

&lt;p&gt;From there we would have the access to current host name which would be the domain.&lt;/p&gt;




&lt;h3&gt;
  
  
  3- Now we will add some code to make sense of the user’s domain.
&lt;/h3&gt;

&lt;p&gt;Add a root route that would point to a controller action, you can name it anything.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'profiles#index'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfilesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="vi"&gt;@user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;custom_domain: &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s1"&gt;'errors/not_found'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="s1"&gt;'error'&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s1"&gt;'profile/show'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="s1"&gt;'profile_layout'&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We check for the host name and see if it exists and return relevant profile.&lt;/p&gt;

&lt;p&gt;This is the bare bones that we would require to handle custom domain workflow in our app.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note for Apps running on PaaS like heroku, render or flyio.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These platforms require you to add that custom domain in their settings as well to make sense of any request coming in, so there proxy servers can forward that request to your app. These platforms normally expose public API’s to do so.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hope you liked it, feel free to ask away any questions you have.&lt;/p&gt;




&lt;p&gt;My name is Zain and I am building &lt;a href="https://devtree.app?utm_source=devto" rel="noopener noreferrer"&gt;devtree&lt;/a&gt; where developers can get hired without any job search.&lt;/p&gt;

&lt;p&gt;I post about my journey, lessons learned and success on &lt;a href="https://twitter.com/zainnazirbutt" rel="noopener noreferrer"&gt;twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/zainnazirbutt" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;. You will also find other things on my devtree profile as well.&lt;/p&gt;

&lt;p&gt;If you want to learn about working on Startups, Rails and general life advice follow me.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Moving to solid_queue from sidekiq</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Thu, 28 Dec 2023 14:16:40 +0000</pubDate>
      <link>https://dev.to/zainbutt/moving-to-solidqueue-from-sidekiq-47a0</link>
      <guid>https://dev.to/zainbutt/moving-to-solidqueue-from-sidekiq-47a0</guid>
      <description>&lt;p&gt;A little bit about me, I am an engineer turned indiehacker for the first time and working on my startup &lt;a href="https://devtree.app?utm_source=devto" rel="noopener noreferrer"&gt;devtree&lt;/a&gt;. I started working on it in July this year and growing it slowly.&lt;/p&gt;

&lt;p&gt;Its a simple Ruby on Rails application running on Flyio backed by Postgres and background jobs running with Sidekiq and redis.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;I use Upstash serverless Redis in my app that is provided by Flyio with their tight integration with Upstash.&lt;/p&gt;

&lt;p&gt;Upstash pricing is per request based, which was different for apps running on flyio as they were providing a free tier based on memory restrictions which worked for me.&lt;/p&gt;

&lt;p&gt;But last month they decided to unify their pricing everywhere after new year on 1st Jan. Based on my setup with sidekiq, it sends gazillion request per hour to check for new jobs which eats up their free quota of 10k requests per day.&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%2Fy3kgwa8f97av3c4k6bzl.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%2Fy3kgwa8f97av3c4k6bzl.png" alt="upstash redis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As much I like sidekiq, I can't bear the redis costs when I am not making any money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;I was looking for alternative solutions specifically non-redis based. I had a few suggestions from my network which included &lt;code&gt;solid_queue&lt;/code&gt; which surprisingly I forgot about.&lt;/p&gt;

&lt;p&gt;Its a non-redis solution, works with postgres and I wouldn't spend weeks implementing it. So, I decided to give it a try.&lt;/p&gt;

&lt;p&gt;Here's the process I followed:&lt;/p&gt;

&lt;p&gt;1 - &lt;strong&gt;Create a new branch&lt;/strong&gt;&lt;br&gt;
2 - &lt;strong&gt;Add the gem&lt;/strong&gt;&lt;/p&gt;

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

gem 'solid_queue'



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

&lt;/div&gt;

&lt;p&gt;3 - &lt;strong&gt;Change the active job adapter&lt;/strong&gt;&lt;/p&gt;

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

config.active_job.queue_adapter = :solid_queue



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

&lt;/div&gt;

&lt;p&gt;4 - &lt;strong&gt;Install solid queue&lt;/strong&gt;&lt;/p&gt;

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

rails generate solid_queue:install



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

&lt;/div&gt;

&lt;p&gt;5 - &lt;strong&gt;Run migrations for job tables&lt;/strong&gt;&lt;/p&gt;

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

rails solid_queue:install:migrations
rails db:migrate



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

&lt;/div&gt;

&lt;p&gt;6 - &lt;strong&gt;Run the worker&lt;/strong&gt;&lt;/p&gt;

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

bundle exec rake solid_queue:start
# or add it in Procfile.dev
# solid: bundle exec rake solid_queue:start



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

&lt;/div&gt;

&lt;p&gt;Now you can create your first job&lt;/p&gt;

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

rails g job my_job

# app/jobs/my_job.rb

class MyJob &amp;lt; ApplicationJob
  self.queue_adapter = :solid_queue
  # ...
end



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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Concepts
&lt;/h2&gt;

&lt;p&gt;Solid queue will create a few tables for you to store your jobs but focus on 2 for now. &lt;br&gt;
&lt;code&gt;solid_queue_scheduled_executions&lt;/code&gt; and &lt;code&gt;solid_queue_ready_executions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can guess from their names, one is used to store jobs when they are to be run in the future.&lt;/p&gt;

&lt;p&gt;The other is to store jobs which need immediate execution.&lt;/p&gt;
&lt;h3&gt;
  
  
  Dispatchers
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Dispatchers&lt;/code&gt; are in charge of selecting jobs scheduled to run in the future that are due and dispatching them, which is simply moving them from the &lt;code&gt;solid_queue_scheduled_executions&lt;/code&gt; table over to the &lt;code&gt;solid_queue_ready_executions&lt;/code&gt; table so that workers can pick them up. They also do some maintenance work related to concurrency controls.&lt;/p&gt;
&lt;h3&gt;
  
  
  Workers
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Workers&lt;/code&gt; are in charge of picking jobs ready to run from queues and processing them. They work off the &lt;code&gt;solid_queue_ready_executions&lt;/code&gt; table&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;You can also configure the polling interval, number of workers based on your requirements by using a yaml configuration file.&lt;/p&gt;

&lt;p&gt;add a configuration file in config/solid_queue.yml:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

development:
  dispatchers:
    - polling_interval: 5 #in seconds
      batch_size: 100
  workers:
    - queues: '*'
      threads: 5
      processes: 1
      polling_interval: 5 #in seconds


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

&lt;/div&gt;

&lt;p&gt;With this configuration, it will spin 5 worker threads to process the jobs every 5 seconds.&lt;/p&gt;

&lt;p&gt;There are tons of other job level and queue level configurations that you can add for better control over concurrency, uniqueness and queue management that you can find &lt;a href="https://github.com/basecamp/solid_queue?tab=readme-ov-file#configuration" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveat
&lt;/h2&gt;

&lt;p&gt;I have been monitoring my app for a few days and unfortunately it has crashed a few times due out of memory which never happened before, seems like 512mb ram is not enough 🤷.&lt;/p&gt;

&lt;p&gt;I haven't debugged the issue for now but will look into it for the root cause.&lt;/p&gt;

&lt;p&gt;This is it form side, let me know if you would like to know more about the technical side of my startup.&lt;br&gt;
I share about my startup publicly on &lt;a href="https://twitter.com/zainnazirbutt" rel="noopener noreferrer"&gt;twitter&lt;/a&gt; and &lt;a href="https://linkedin.com/in/zainnazirbutt" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>watercooler</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I made a reverse job board for developers</title>
      <dc:creator>Zain Butt</dc:creator>
      <pubDate>Tue, 26 Dec 2023 21:02:58 +0000</pubDate>
      <link>https://dev.to/zainbutt/i-made-a-reverse-job-board-for-developers-49hp</link>
      <guid>https://dev.to/zainbutt/i-made-a-reverse-job-board-for-developers-49hp</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;I am Zain, an indiehacker from Pakistan.&lt;/p&gt;

&lt;p&gt;I was laid off from my job last year and was frustrated to find another job. I applied on several jobs on dozens of job boards only to be ghosted or rejected.&lt;/p&gt;

&lt;p&gt;This experience made me realise how much time and energy it takes, how many times we need to write the cover letters and manually add our details every time even when we upload our resume, so I decided to change this.&lt;/p&gt;




&lt;p&gt;That's why I built devtree, where you are in control. For this project I used what I know the best, &lt;code&gt;Ruby on Rails&lt;/code&gt; and took a chance to learn &lt;code&gt;Hotwire&lt;/code&gt; and &lt;code&gt;tailwindCSS&lt;/code&gt; and let me tell you its been worth it. On top of &lt;code&gt;tailwind&lt;/code&gt; I used &lt;code&gt;daisyUI&lt;/code&gt; to get component based classes.&lt;/p&gt;

&lt;p&gt;I bootstrapped my startup so cost savings is fundamental, I relied on heroku's free tier but that was not an option since they moved to paid only plans. So, I searched for an alternative and found &lt;a href="https://fly.io"&gt;fly.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I run three instances their which includes my web app, background worker and database all for free.&lt;/p&gt;




&lt;p&gt;The app allows the developers to choose a username, add projects/links, build a testimonial page, add skills, work preferences and personal details. Using this data they can create a portfolio or proof of work site which is easily shareable using their usernames as it contains all their work in one place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo0g00jb2c9d2e8htb2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo0g00jb2c9d2e8htb2n.png" alt="zain devtree profile" width="800" height="987"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are a developer and tired of applying to every other job and still getting no results, head on to devtree.&lt;/p&gt;




&lt;p&gt;I will write more about technical stuff in separate posts about different design decisions and integrations. So, stay tuned.&lt;/p&gt;

&lt;p&gt;👉🏻 check the app here: &lt;a href="https://devtree.app?utm_source=devto"&gt;devtree&lt;/a&gt;&lt;br&gt;
👉🏻 you can find me here: &lt;a href="https://devtree.app/zain?utm_source=devto"&gt;devtree/zain&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tailwindcss</category>
      <category>hotwire</category>
    </item>
  </channel>
</rss>
