module Api
module V1
class PostsController < BaseController
before_action :authenticate_user!
def create
class ApplicationError < StandardError
attr_reader :context
class << self
def context_keys(*keys)
@context_keys = keys unless keys.empty?
class ArticlesController < ApplicationController
def index
# Bounded queries: without preload, article.author in the view raises.
@articles = Article
.published
.preload(:author, :tags)
import { Controller } from "@hotwired/stimulus"
import { NotificationsApi } from "notifications_api"
export default class extends Controller {
static targets = ["notification"]
static values = {
class InventoryLevel < ApplicationRecord
belongs_to :warehouse
UPSERT_COLUMNS = %w[warehouse_id sku on_hand reserved updated_at].freeze
def self.upsert_counts(rows)
module TimeAgoHelper
def time_ago_tag(time, locale: I18n.locale, **options)
return if time.blank?
time = time.to_time
fallback = l(time, format: :short)
class Order < ApplicationRecord
class InvalidTransition < StandardError; end
enum status: { pending: 0, paid: 1, shipped: 2, cancelled: 3 }
has_many :order_transitions, -> { order(:created_at) }, dependent: :destroy
class Product < ApplicationRecord
has_many :reviews, dependent: :destroy
scope :published, -> { where(published: true) }
def average_rating
class User < ApplicationRecord
normalizes :phone, with: ->(value) { PhoneNormalizer.call(value) }, apply_to_nil: false
validates :phone,
presence: true,
uniqueness: { case_sensitive: false },
class Comment < ApplicationRecord
belongs_to :post
belongs_to :author, class_name: "User"
validates :body, presence: true
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["field"]
validateField(event) {
<%# Subscribe every viewer of this post to its broadcasts %>
<%= turbo_stream_from @post %>
<%# Update the acting user's button to reflect the toggle %>
<%= turbo_stream.replace dom_id(@post, :like_button) do %>
<%= render "posts/like_button", post: @post %>