TILs - Fueling Curiosity, One Insight at a Time

At Codemancers, we believe every day is an opportunity to grow. This section is where our team shares bite-sized discoveries, technical breakthroughs and fascinating nuggets of wisdom we've stumbled upon in our work.

Published
Author
user-image
Mohammad
When to use collection_select over select in rails
Use collection_select when you need to populate a dropdown with a collection of ActiveRecord objects. It is built on top of select and provides a convenient way to display object attributes instead of a simple array of strings.
select is used for manually defining options, typically from an array of strings or key-value pairs.
collection_select is specifically designed for selecting records from an ActiveRecord collection, making it useful when working with database associations.
Published
Author
user-image
Nived
Rake tasks in Rails let you run custom scripts from the command line.
You can define your own tasks inside the lib/tasks directory.

How to Create a Custom Rake Task

1. Create a new .rake file in lib/tasks/

Code

touch lib/tasks/custom_tasks.rake


Define the task inside the file:

Code

namespace :custom do
  desc "Say hello from a custom rake task"
  task :hello do
    puts "Hello from custom Rake task!"
  end
end


Run the task from the terminal:

Code

bin/rake custom:hello


Use :environment if your task interacts with the database or models

#CU6U0R822 #rake
Published
Author
user-image
Nived
The inverse_of option in ActiveRecord helps Rails recognize bidirectional associations in memory, reducing redundant database queries.
For example:

Code

class Employee < ApplicationRecord
  belongs_to :department, foreign_key: 'department_code', primary_key: 'code', inverse_of: :employees
end

class Department < ApplicationRecord
  has_many :employees, foreign_key: 'department_code', primary_key: 'code', inverse_of: :department
end


Why Use inverse_of?
• Prevents extra queries when accessing related objects
• Keeps objects in memory, improving performance
• Ensures associated objects reference the same instance
Without inverse_of, Rails may reload the association unnecessarily:


Code

employee = Employee.first
department = employee.department  # Triggers a SQL query
department.employees.include?(employee)  # Without `inverse_of`, this could trigger another query


With inverse_of, Rails avoids the extra query because it knows department.employees already includes employee

#CU6U0R822 #active_record
Published
Author
user-image
Nived
In dry-validation contracts, values is a hash containing all the parameters being validated. When defining rule blocks, you can access specific parameters using hash-like syntax.
Example:

Ruby

class MyContract < Dry::Validation::Contract
  params do
    required(:category).filled(:string)
  end

  rule(:category) do
    key.failure("is not allowed") unless values[:category] == "approved_value"
  end
end


Key Points:
values holds all input parameters.
• Use values[:key] to access specific parameters inside rule blocks.
• This allows custom validation logic beyond basic schema definitions.
#ruby #dry_validation
Published
Author
user-image
Nived
You can manually send messages to a Kafka topic using Karafka's producer. This is useful for debugging, testing, or custom event handling.
Example:

Ruby

payload = {
  id: 123,
  name: "Sample Item",
  status: "processed",
  timestamp: 
Time.now.to_i
}

Karafka.producer.produce_sync(
  topic: "your_topic_name",
  payload: payload.to_json
)


Key Points:
produce_sync ensures the message is sent before proceeding.
topic specifies the Kafka topic where the message will be published.
payload should be serialized into JSON or another supported format.
#karafka
Published
Author
user-image
Nitturu
Searching in vector databases

1️⃣ Convert Text to Embeddings
• Text is transformed into numerical vectors using AI models like OpenAI, BERT, or Sentence Transformers.
2️⃣ Index & Organise Embeddings
• Instead of scanning all vectors, the database groups similar embeddings into clusters (buckets) to speed up search.
• Common indexing methods:
HNSW (Hierarchical Navigable Small World) – builds a graph where similar embeddings are connected, reducing search time.
IVFFLAT (Inverted File Index) – divides embeddings into clusters (buckets) and searches only the most relevant ones.
3️⃣ Search Using Similarity Metrics
• The query is converted into an embedding and compared to stored vectors using:
Cosine Similarity: Cosine Similarity measures the angle between vectors while ignoring their magnitude, where a higher value means greater similarity (1 = identical, 0 = unrelated, -1 = opposite). It is commonly used for text similarity, such as document searches.
Euclidean Distance: Euclidean Distance calculates the straight-line distance between points, where a lower value means greater similarity (0 = identical). This method is ideal for spatial data, like image or geographical searches.
• The database searches only the closest clusters, making it faster.
4️⃣ Return the Closest Matches
• The best matches (top K documents) are ranked and returned based on similarity scores.
📌 Convert text → embeddings, group them into clusters, search only relevant ones, return the top K ranked results.

#vectordatabase
Published
Author
user-image
Nitturu
RAG has three key steps:
1️⃣ Retrieval – Fetch relevant context from a vector database.
2️⃣ Augmentation – Inject the retrieved context into the prompt.
3️⃣ Generation – Use an LLM (GPT, Llama, etc.) to produce a fact-based response.

🔹 Step 1: Retrieval – Finding Relevant Information
Before answering a question, the system searches for relevant documents in a vector database.
💬 Example Question: "What is the capital of France?"
🔍 Retrieval Process:
• The system searches for relevant text in a vector database.
• It finds a stored Wikipedia snippet:
Paris is the capital of France, known for the Eiffel Tower.

📌 Retrieved Context:
Paris is the capital of France, known for the Eiffel Tower.

🔹 Step 2: Augmentation – Enriching the Prompt with Context
After retrieving relevant information, the system adds it to the prompt.

📌 Final Augmented Prompt:
User Question: "What is the capital of France?"
Retrieved Context: "Paris is the capital of France, known for the Eiffel Tower."
Final Prompt: "Using the provided context, answer: What is the capital of France?"

👉 Why is this useful?
Retrieval ensures AI has up-to-date context instead of relying only on pre-trained data.
Augmentation refines the LLM’s input, making answers more precise.
Reduces hallucinations, ensuring the AI doesn’t generate incorrect facts.

🔹 Step 3: Generation – Producing the Final Answer
Once the AI has retrieved and augmented the prompt, it generates a final response.
💡 Example Output:
"The capital of France is Paris, known for the Eiffel Tower and rich history."

#AI #RAG
Published
Author
user-image
Adithya Hebbar
System Analyst
Updating Session in NextAuth

In NextAuth, you can update the session data using the update function from useSession(). Here's how you can modify user details dynamically:

JavaScript

const { data: session, update } = useSession();

await update({
  user: {
    ...session?.user,
    name: "Updated Name",
    role: "editor", 
  },
});


Assuming a strategy: "jwt" is used, the update() method will trigger a jwt callback with the trigger: "update" option. You can use this to update the session object on the server.


JavaScript

export default NextAuth({
  callbacks: {
    // Using the `...rest` parameter to be able to narrow down the type based on `trigger`
    jwt({ token, trigger, session }) {
      if (trigger === "update" && session?.name) {
        // Note, that `session` can be any arbitrary object, remember to validate it!
        token.name = session.name
        token.role = session.role
      }
      return token
    }
  }
})


This updates the session without requiring a full reload, ensuring the UI reflects the changes immediately. 🚀

#next-auth #nextjs
Published
Author
user-image
Puneeth
Traits in FactoryBot helps to define reusable variations of a factory without creating multiple factories. They are useful when we need optional attributes or specific states in test data.
Let's say we have a User model with different roles (admin, regular, guest). Instead of writing separate factories, we can use traits like below:

Ruby

# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    first_name { Faker::Name.first_name }
    email { Faker::Internet.unique.email }
    password { "password123" }

    trait :admin do
      role { "admin" }
    end

    trait :guest do
      role { "guest" }
    end

    trait :confirmed do
      confirmed_at { Time.current }
    end
  end
end


And use it like below

Ruby

let(:admin_user) { create(:user, :admin) }
let(:guest_user) { create(:user, :guest) }
let(:confirmed_user) { create(:user, :confirmed) }


#CU6U0R822 #factory_bot
Published
Author
user-image
Nived
In Ruby, public_send allows calling a method dynamically when its name is stored in a variable.

Why Use public_send?
Instead of calling methods explicitly, we can determine the method name at runtime and call it dynamically.

Example: Handling Different Attribute Names

Ruby

quantity_field = item.respond_to?(:ordered_quantity) ? :ordered_quantity : :quantity
new_quantity = item.public_send(quantity_field).to_i + item_case[:quantity].to_i


• If item has ordered_quantity, it calls item.ordered_quantity
• Otherwise, it calls item.quantity
• This avoids unnecessary if-else statements
#ruby
Published
Author
user-image
Nived
In Ruby, there are two ways to define hash keys:

1. Using the Colon Syntax (:) – Creates a Literal Symbol Key

Ruby

item.update!(
  ordered_quantity: new_quantity,
)


Key Behavior: The key is treated as a fixed symbol (e.g., :ordered_quantity).

2. Using the Hash Rocket (=>) – Evaluates the Left-Hand Side as a Key

Ruby

item.update!(
  quantity_field => new_quantity,
)


Key Behavior: The left-hand side is evaluated dynamically, making it useful for variable-based keys.

Example Use Case: Dynamic Keys

Ruby

quantity_field = item.respond_to?(:ordered_quantity) ? :ordered_quantity : :quantity
new_quantity = item.public_send(quantity_field).to_i + item_case[:quantity].to_i

item.update!(
  quantity_field => new_quantity,  # Evaluates to :ordered_quantity or :quantity
)


Here, quantity_field is determined dynamically based on the model, so => must be used instead of :.

When to Use =>?
• When working with multiple models that have different column names
• When dynamically generating hash keys at runtime
• When building flexible APIs that handle varying attribute names
Takeaway:
• Use : when the key is static and always the same.
• Use => when the key is stored in a variable or needs to be evaluated dynamically.
#ruby
Published
Author
user-image
Nived
In Ruby, attr_reader automatically creates a getter method for instance variables, making code cleaner and more concise. Instead of writing:

Ruby

def some_number
  @some_number
end


You can simply use:

Ruby

attr_reader :some_number


This makes attributes read-only while keeping the class lightweight

#ruby #CU6U0R822
Published
Author
user-image
Nitturu
Real-time AI response streaming improves user experience by reducing wait times and making interactions feel more dynamic. Instead of waiting for the entire response to be generated before displaying it, streaming allows data to be processed and presented incrementally.

Example of AI response streaming using Nest Js backend and Next JS front end.

Setting Up the NestJS Backend for Streaming AI Responses

Controller


Code

import { Controller, Post, Body, Res } from '@nestjs/common';
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
import { Response } from 'express';

@Controller('orchestrator')
export class OrchestratorController {

 @Post('chat')
 async chat(@Body() payload: any, @Res() res: Response) {
  const { messages } = payload;

  const result = streamText({
   model: openai('gpt-4o'),
   messages,
  });
   
  result.pipeDataStreamToResponse(res); // Streams the AI response directly to the client
 }
}


How It Works
• The @Post('chat') endpoint listens for chat requests.
• The streamText function sends user messages to OpenAI and receives a streamed response.
pipeDataStreamToResponse(res) directly streams the AI-generated content to the client as it arrives.
Building the Next.js Frontend for AI Response Streaming

chat/page.tsx


Code

'use client';

import { useChat } from '@ai-sdk/react';

export default function Home() {
 const { messages, input, handleInputChange, handleSubmit } = useChat({
  api: 'https://localhost:3000/api/orchestrator/chat',  // make the post request to the NestJS backend
 });

 return (
  <div>
   {messages.map((message) => (
    <div key={message.id}>
     {message.role === 'user' ? 'User: ' : 'AI: '}
     {message.content}
    </div>
   ))}

   <form onSubmit={handleSubmit}>
    <input
     name="prompt"
     value={input}
     onChange={handleInputChange}
     className="text-black"
    />
    <button type="submit">Submit</button>
   </form>
  </div>
 );
}


How It Works
• The useChat hook from AI-SDK manages state and streaming logic automatically.
• It sends user messages to the backend and updates the UI in real time as responses arrive.
• The messages array dynamically updates, displaying each chunk of AI-generated text as it's received.
#C08DPTN3JAW #streaming #next js #nest js
Published
Author
user-image
Puneeth
Collection caching is a way to speed up rendering multiple items on a page by storing their HTML in cache.
How it works:
1. When we use <%= render partial: 'products/product', collection: @products, cached: true %>, Rails checks if each product's HTML is already stored in the cache.
2. If a product’s HTML is found in the cache, Rails loads it quickly instead of rendering it again.
3. If a product’s HTML is not in the cache, Rails will render it, store it in the cache, and use it next time.
4. The big advantage: Rails fetches all cached products at once (instead of one by one), making it much faster.
#CU6U0R822 #caching #collection_caching
Published
Author
user-image
Nived
When testing with Capybara, you might need to scroll an element into view before interacting with it. Instead of using JavaScript like:

JavaScript

page.execute_script("arguments[0].scrollIntoView(true)", button)


You can use Capybara's built-in method:

JavaScript

scroll_to(button)  # Scrolls to the element


This is available in
Capybara 3.26+
and is the preferred way to ensure visibility before clicking or interacting with an element.

#capybara #CU6U0R822 #C041BBLJ57G
Published
Author
user-image
Nived
In JavaScript, you can use localeCompare with { sensitivity: "base" } to compare strings without considering case or accents.
Example:


JavaScript

"Test".localeCompare("test", undefined, { sensitivity: "base" }) === 0; // ✅ True
"café".localeCompare("cafe", undefined, { sensitivity: "base" }) === 0; // ✅ True
"Hello".localeCompare("HELLO", undefined, { sensitivity: "base" }) === 0; // ✅ True


• Case-insensitive
Accent-insensitive
No need for toLowerCase() hacks anymore! 🎉

second argument is locale . by giving it as "Undefined" it uses default locale of the runtime environment. We can specify as "en", "id" etc. It is used in sorting scenarios ig.

Sensitivity is the behaviour of the comparison


JavaScript

"base" → Ignores case & accents ("café" == "cafe", "Hello" == "hello")

"accent" → Considers accents but ignores case ("café" != "cafe", "Hello" == "hello")

"case" → Considers case but ignores accents ("café" == "cafe", "Hello" != "hello")

"variant" → Considers both case & accents ("café" != "cafe", "Hello" != "he



#stimulus #JavaScript #StringComparison
Published
Author
user-image
Nived
By default, Capybara only finds visible and interactable elements. If a button is disabled or outside the viewport, Capybara may fail to locate it.
To fix this, use:


Code

expect(page).to have_button("Add Discrepancy", disabled: true, visible: :all)


disabled: true ensures the button is actually disabled
visible: :all allows Capybara to find buttons that are hidden, off-screen, or disabled
This is useful when testing UI behaviors where buttons are conditionally enabled/disabled or require scrolling to be visible.

#CU6U0R822 #capybara #C041BBLJ57G #specs
Published
Author
user-image
Puneeth
local_assigns :
When using partial views in Rails (like _partial.html.erb), we might pass local variables to customize the rendering. However, if we try to use a local variable that wasn't passed, Rails will raise an error.
To avoid this, local_assigns is a special hash that helps check if a local variable was provided when rendering the partial. Instead of directly using <%= show_projects %>, which could cause an error if missing, we can safely check local_assigns[:show_projects] first.


Ruby

<% if local_assigns[:show_projects] %> 
  <div class="flex">
    <%= (render @user.projects) || (render 'shared/empty_state', message: "No projects found!") %>
  </div> 
<% end %>


Here, the partial checks if show_projects was passed before using it. If show_projects was provided, it renders the user's projects or a message if no projects are found. If show_projects wasn't passed, nothing happens, preventing errors.
Published
Author
user-image
Mohammad
The Rails 8.0 release introduces several new features, and among them, params#expect stands out.

In our daily work with Rails, we often rely on params#require for assignments and queries. However, params#require is more explicit than permit. Here’s an example to illustrate:


Ruby

params = ActionController::Parameters.new(posts: [{id: 1}])


If you expect the posts parameter to contain a list of IDs, such as [{id: 1}, {id: 2}], you can define your expectations like this:


Ruby

params.expect(posts: [[:id]])


The output will be:

Ruby

[
  #<ActionController::Parameters {"id"=>1} permitted: true>,
  #<ActionController::Parameters {"id"=>2} permitted: true>
]


Now, consider a different scenario where you expect the posts parameter to have only a single hash with an ID, like this:


Ruby

params = ActionController::Parameters.new(posts: {id: 1})


If you use:


Ruby

params.expect(posts: [[:id]])


It will raise the following error:

ActionController::ExpectedParameterMissing: param is missing or the value is empty or invalid: posts
In contrast, using the older params#permit:


Ruby

params.permit(posts: [:id])


Will not enforce your expectation of the nested parameter structure and will accept it without validation.
Published
Author
user-image
Giritharan
System Analyst
Rails Inflections:
What is it? Inflections in Rails, powered by the ActiveSupport::Inflector module, allow customization of how words are pluralized, singularized, or treated as uncountable.
Why use it? Sometimes Rails' default pluralization rules don't fit your app's needs (e.g., irregular words like footfeet, uncountable words like milk).

Examples

Default Behavior:

Code

"person".pluralize  # => "people"
"person".singularize # => "person"


Irregular Inflections:

Code

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular "foot", "feet"
end

// "foot".pluralize  # => "feet"


Uncountable Words:

Code

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.uncountable "milk"
end

// "milk".pluralize  # => "milk"


Acronym Inflections:

Code

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym "HTML5"
end

// "html5".camelize  # => "HTML5"


Potential Issues:
Default Behavior May Be Inaccurate: Without customizing, words like "tooth" become "tooths" or "milk" becomes "milks."
Localization: Inflections are locale-specific, so customizations for one locale won't apply to others.
Best Practice: Always define rules for edge cases (irregular, uncountable, acronyms) in your config/initializers/inflections.rb ans restart the server after changes

#rails-inflections #active-support #CU6U0R822

Showing page 5 of 42

Your competitors are already using AI.
The question is how fast you want to unlock the value.

Don't know where to start?

AI is everywhere but it's unclear which investments will actually move your metrics and which are expensive experiments.

Your data isn't ready

Most AI projects fail at the data layer. Pipelines, quality, access all need work before LLMs can deliver value.

Internal teams are stretched

Your engineers are shipping product. They don't have capacity to also become AI specialists with production-grade experience.

Legacy systems block everything

Aging, undocumented codebases make AI integration slow, risky, and expensive. They need to move first.

Don't worry. We've got you covered.

Start with the audit.