Rails.application.config.middleware.insert_before 0, Rack::Cors do
# Development CORS - allow any localhost
allow do
origins(
/http:\/\/localhost:\d+/,
/http:\/\/127\.0\.0\.1:\d+/,
import { memo } from 'react'
import { Post } from '@/types'
interface PostListItemProps {
post: Post
onLike: (id: string) => void
Rails.application.configure do
# Bullet configuration
config.after_initialize do
Bullet.enable = true
Bullet.alert = true # Show JavaScript alert
Bullet.bullet_logger = true # Log to bullet.log
import { useEffect } from 'react'
interface KeyboardHandlers {
[key: string]: () => void
}
FactoryBot.define do
factory :post do
association :author, factory: :user
sequence(:title) { |n| "Post Title #{n}" }
body { Faker::Lorem.paragraphs(number: 3).join("\n\n") }
status { :draft }
import { ReactNode, useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
interface PortalProps {
children: ReactNode
container?: Element
class AddStatusToPosts < ActiveRecord::Migration[6.1]
# Use change for automatic rollback
def change
# Add column without default to avoid table lock
add_column :posts, :status, :string
import { Suspense } from 'react'
import { useSuspenseQuery } from '@tanstack/react-query'
import { useParams } from 'react-router-dom'
import api from '@/services/api'
import { Post } from '@/types'
import { ErrorBoundary } from '@/components/ErrorBoundary'
class Post < ApplicationRecord
# View counter - increments without hitting the database
kredis_counter :view_count, expires_in: 1.day
# Recent viewers list - stores last 10 viewer IDs
kredis_unique_list :recent_viewers, limit: 10
import { useState, useMemo, useCallback } from 'react'
import { Post } from '@/types'
import { PostCard } from './PostCard'
interface FilteredPostsProps {
posts: Post[]
module Paginatable
extend ActiveSupport::Concern
included do
before_action :set_pagination_params, only: [:index]
end
import { ReactNode } from 'react'
interface CardProps {
children: ReactNode
className?: string
}