CtrlK
BlogDocsLog inGet started
Tessl Logo

igmarin/hanakai-yaku

Curated library of atomic skills and personas for Hanami, dry-rb, and ROM Ruby development. Covers actions, slices, repositories, relations, changesets, providers, DI, operations, TDD, CLI, views, routing, validation, and 10 orchestration personas. Shared Ruby process skills have moved to ruby-core-skills. Uses Markdown + Front-matter architecture.

95

1.20x
Quality

95%

Does it follow best practices?

Impact

96%

1.20x

Average score across 45 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

SKILL.mdskills/views/decorate-with-parts/

name:
decorate-with-parts
license:
MIT
type:
atomic
description:
Use when creating View Parts for decorator-style logic in Hanami 2.x — define Part classes inheriting from `Hanami::View::Part`, delegate attributes to the wrapped value via `delegate :name, :email, to: :value`, expose data as a Part in Views with `expose :model, as: :model_part`, add presentation methods returning formatted strings or booleans (no HTML generation and no database queries in Parts), and access the raw underlying object via the `value` method when needed. Defines Part classes that encapsulate presentation logic, keeps templates free of complex formatting, and exposes them via the `expose` macro.
metadata:
{"ecosystem_sources":["hanami/hanami-view"],"tags":["views","parts","decorators","presentation"],"version":"1.0.0"}

decorate-with-parts

Use this skill when creating View Parts for decorator-style logic in Hanami 2.x.

Core principle: Parts wrap data with presentation methods. They keep Views and templates free of complex formatting logic.


Quick Reference

ScenarioApproach
Create a PartClass inherits from Hanami::View::Part
Expose as a Partexpose :user, as: :user_part
Define Part methodsAdd methods to the Part class for presentation logic
Access wrapped datavalue method returns the raw underlying object
Delegate to wrapped datadelegate :name, :email, to: :value
Use in template<%= user_part.display_name %>
Format datadef formatted_date; value.created_at.strftime("%B %d, %Y"); end
Generate HTMLKeep HTML generation out of Parts. Use helpers or template logic.

Core Rules

  1. Create the Part class:

    # app/views/parts/user.rb
    # frozen_string_literal: true
    
    module MyApp
      module Views
        module Parts
          class User < Hanami::View::Part
            delegate :name, :email, to: :value
    
            def display_name
              "#{value.first_name} #{value.last_name}"
            end
    
            def member_since
              value.created_at.strftime("%B %Y")
            end
    
            def admin?
              value.role == "admin"
            end
          end
        end
      end
    end
  2. Expose data as a Part in the View:

    class Show < MyApp::View
      expose :user, as: :user_part
    end
  3. Use Part methods in templates:

    <h1><%= user_part.display_name %></h1>
    <p>Member since <%= user_part.member_since %></p>
    
    <% if user_part.admin? %>
      <span class="badge">Admin</span>
    <% end %>
  4. Keep Parts focused on presentation. No database queries, no business rules:

    # GOOD: formatting and simple predicates
    def display_name
      "#{value.first_name} #{value.last_name}"
    end
    
    # BAD: business logic
    def can_delete?(resource)
      value.role == "admin" && resource.owner_id == value.id
    end
  5. Delegate common methods to the wrapped value:

    delegate :id, :name, :email, :created_at, to: :value
  6. Access the raw value with the value method when needed:

    def raw_attributes
      value.to_h
    end
  7. Do not generate HTML in Parts. Parts return strings or booleans. Templates handle HTML:

    # GOOD
    def status_label
      value.active? ? "Active" : "Inactive"
    end
    
    # BAD
    def status_badge
      "<span class='badge'>#{status_label}</span>"
    end

Common Mistakes

  • No database queries in Parts. Parts wrap already-fetched data; queries belong in repositories or actions.
  • No HTML generation in Parts. Parts return plain strings or booleans; templates produce HTML markup.
  • No business logic in Parts. Predicates based on simple attribute values are fine; authorization rules and domain decisions belong in interactors or service objects.

Integration

Related SkillWhen to chain
create-viewParts are used within Views. Master View structure first.
create-actionActions pass data to Views, which wrap them in Parts.
define-entityParts often wrap Entity objects returned by Repositories.

skills

views

decorate-with-parts

README.md

tile.json