### Rendered output with :as Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api Example of the resulting JSON output after applying the :as option. ```json song.to_json #=> {"name":"Fallout","track":1} ``` -------------------------------- ### Instantiate Objects for Inheritance Example Source: https://trailblazer.to/2.0/gems/representable/3.0/api Sets up the necessary Structs and instances for demonstrating property inheritance in representers. ```ruby Artist = Struct.new(:name) SongWithArtist = Struct.new(:id, :title, :artist) artist = Artist.new("Ivan Lins") song_with_artist = SongWithArtist.new(1, "Novo Tempo", artist) ``` -------------------------------- ### Nilify Example Source: https://trailblazer.to/2.0/gems/disposable/api Shows how a blank string input is converted to `nil` when `:nilify` is enabled. ```ruby twin.id = "" twin.id #=> nil ``` -------------------------------- ### Parse with user options Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api Example of passing user_options to the parsing method. ```ruby decorator.from_json('{"id":1}', user_options: {is_admin: true}) ``` -------------------------------- ### Rendered output with custom getter Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api Example of the resulting JSON output after applying a custom getter. ```json decorator.to_json #=> {"id": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"} ``` -------------------------------- ### Gemgem-Sinatra project structure Source: https://trailblazer.to/2.0/newsletter/2016-january Directory layout for the Gemgem-Sinatra example application demonstrating Trailblazer with Sinatra and Sequel. ```text ├── app.rb ├── concepts │   └── post │   ├── cell │   │   ├── new.rb │   │   └── show.rb │   ├── operation │   │   ├── create.rb │   │   └── update.rb │   └── view │   ├── new.slim │   └── show.slim ├── config │   ├── init.rb │   └── migrations.rb ├── Gemfile ├── Gemfile.lock ├── models │   └── post.rb ``` -------------------------------- ### Visualize concept directory structure Source: https://trailblazer.to/2.0/gems/trailblazer/loader Example of mixing compound files and explicit directories within a concept. ```text app ├── concepts │ ├── comment │ │ ├── contract.rb - compound vs. │ │ ├── operation - explicit directory │ │ │ ├── create.rb │ │ │ └── update.rb ``` -------------------------------- ### Install Trailblazer Loader Source: https://trailblazer.to/2.0/gems/trailblazer/loader Add the gem to your Gemfile to enable the loader. ```ruby gem 'trailblazer-loader' ``` -------------------------------- ### Installation Dependencies Source: https://trailblazer.to/2.0/gems/cells/trailblazer Add these gems to your Gemfile to use Trailblazer cells and the Slim view engine. ```ruby gem "trailblazer-cells" gem "cells-slim" ``` -------------------------------- ### Controller Logic for Creating a Post Source: https://trailblazer.to/2.0/guides/trailblazer/2.0/01-operation-basics This example shows typical controller logic for handling post creation in a web framework, which Trailblazer Operations aim to abstract. ```ruby class PostsController < RubyOnTrails::Controller def create post = Post.new post.assign_attributes(params[:post]) if post.save notify_current_user! else render end end end ``` -------------------------------- ### Running a Trailblazer Operation Source: https://trailblazer.to/2.0 Operations are run by calling them with a hash of parameters and a hash of dependencies. This example shows how to pass parameters and the current user. ```ruby Song::Create.( { title: "Roxanne", length: 300 }, # params "current_user": current_user # dependencies ) ``` -------------------------------- ### Property Instance with Keyword Arguments Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of defining a property's instance logic using keyword arguments. This is the recommended approach for Ruby 2.1+. ```ruby property :artist, instance: ->(fragment:, user_options:, **) do ``` -------------------------------- ### View Name Resolution Source: https://trailblazer.to/2.0/gems/cells/trailblazer Examples showing how cell class names map to view file paths. ```ruby Comment::Cell::New #=> "comment/view/new.slim" Comment::Cell::Themed::New #=> "comment/view/themed/new.slim" ``` -------------------------------- ### Callback Method Implementation with Options Source: https://trailblazer.to/2.0/gems/disposable/callback Example of a callback method implementation that utilizes options passed during invocation. ```ruby class CallbackImplementation def change!(twin, options) options[:string] << "change!" end ``` -------------------------------- ### Define Models for Twin Constructor Example Source: https://trailblazer.to/2.0/gems/disposable/api Define simple Structs to represent the models that will be decorated by the twin. These are used in the constructor and sync examples. ```ruby Song = Struct.new(:name, :index) Artist = Struct.new(:full_name) Album = Struct.new(:title, :songs, :artist) ``` -------------------------------- ### Grape API Setup with Trailblazer Operations Source: https://trailblazer.to/2.0/guides/grape Defines a Grape API application that routes GET and POST requests for 'posts' to Trailblazer operations like Post::Show and Post::Create. Ensure Trailblazer operations are correctly implemented and accessible. ```ruby module API class Application < Grape::API format :json version :v1 do get("posts") { run!(Post::Show, request) } post("posts") { run!(Post::Create, request) } end end end ``` -------------------------------- ### Define explicit operation directory Source: https://trailblazer.to/2.0/gems/trailblazer/loader Example showing how operations are organized within an explicit directory structure. ```text app ├── concepts │ ├── comment │ │ ├── operation - explicit directory │ │ │ ├── create.rb - contains Comment::Create │ │ │ └── update.rb ``` -------------------------------- ### Property Instance with Keyword Arguments and Binding Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of using keyword arguments to access the `binding` object and `represented` object within a property's instance logic. ```ruby property :artist, instance: ->(binding:, user_options:, **) do binding.represented # the represented object end ``` -------------------------------- ### Populator Return Value Examples Source: https://trailblazer.to/2.0/gems/reform/populator Each populator invocation must return the form representing the fragment, not the model. Returning a model will cause deserialization to fail. ```ruby populator: -> (collection:, index:, **) do songs[index] # works, unless nil collection[index] # identical to above songs.insert(1, Song.new) # works, returns form songs.append(Song.new) # works, returns form Song.new # crashes, that's no form Song.find(1) # crashes, that's no form ``` -------------------------------- ### Cell Definition Example Source: https://trailblazer.to/2.0/gems/cells/api Illustrates the basic structure of a Cell class, inheriting from Cell::ViewModel and defining a show method. ```APIDOC ## Cell Definition Example ### Description This example shows how to define a basic cell class that inherits from `Cell::ViewModel` and implements the `#show` method to render a view. ### Method N/A (Class Definition) ### Endpoint N/A ### Parameters N/A ### Request Example ```ruby class CommentCell < Cell::ViewModel def show render # renders app/cells/comment/show.haml end end ``` ### Response N/A ``` -------------------------------- ### Define a JSON API representer Source: https://trailblazer.to/2.0/gems/roar/jsonapi A comprehensive example showing how to define a resource, top-level links, attributes, and relationships. ```ruby class ArticleDecorator < Roar::Decorator include Roar::JSON::JSONAPI.resource :articles # top-level link. link :self, toplevel: true do "//articles" end attributes do property :title end # resource object links link(:self) { "http://#{represented.class}/#{represented.id}" } # relationships has_one :author, class: Author, populator: ::Representable::FindOrInstantiate do # populator is for parsing, only. type :authors attributes do property :email end link(:self) { "http://authors/#{represented.id}" } end has_many :comments, class: Comment, decorator: CommentDecorator end ``` -------------------------------- ### Install Trailblazer Gem Source: https://trailblazer.to/2.0/guides/trailblazer-in-20-minutes Add the Trailblazer gem to your application's Gemfile for basic functionality. The `trailblazer` or `trailblazer-rails` gems are usually sufficient. ```ruby gem "trailblazer" ``` -------------------------------- ### Coercion Example Source: https://trailblazer.to/2.0/gems/disposable/api Demonstrates type coercion where a string input is converted to an integer. ```ruby twin.id = "1" twin.id #=> 1 ``` -------------------------------- ### Operation with Multiple Failure Tracks Source: https://trailblazer.to/2.0/blog/2017-12-trailblazer-2-1-what-you-need-to-know This example demonstrates using multiple 'fail' tracks with specific output connections, allowing for complex control flow and recovery patterns beyond the standard success/failure tracks. ```ruby class Memo::Upload < Trailblazer::Operation step :upload_to_s3 fail :upload_to_azure, Output(:success) => :success fail :upload_to_b2, Output(:success) => :success fail :log_problem # ... end ``` -------------------------------- ### Install Reform with ActiveModel Source: https://trailblazer.to/2.0/gems/reform Add the required gems to your Gemfile and configure the initializer to use ActiveModel validations. ```ruby gem "reform" gem "reform-rails" ``` ```ruby require "reform/form/active_model/validations" Reform::Form.class_eval do include Reform::Form::ActiveModel::Validations end ``` -------------------------------- ### Configure Render Filter Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of configuring a custom render filter lambda. This lambda formats a value and includes document and options data. ```ruby :render_filter => lambda { |val, options| "#{val.upcase},#{options[:doc]},#{options[:options][:user_options]}" } ``` -------------------------------- ### Property Instance with Generic Options Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of accessing runtime information like `represented` and `user_options` via the generic `options` hash within a property's instance logic. ```ruby property :artist, instance: ->(options) do options[:binding] # property Binding instance. options[:binding].represented # the represented object options[:user_options] # options from user. end ``` -------------------------------- ### Define Roles Array for Select Options Source: https://trailblazer.to/2.0/gems/formular/bootstrap An example array defining options for a select box, where each option is a pair of display text and value. ```ruby roles_array = [["Admin", 1], ["Owner", 2], ["Maintainer", 3]] ``` -------------------------------- ### Receiving Arguments in Cell Methods Source: https://trailblazer.to/2.0/gems/cells/api Shows how a cell method can accept arguments passed during invocation. The example shows a `time` argument being received. ```ruby def show(time) time #=> Now! end ``` -------------------------------- ### Populator for Single Property Source: https://trailblazer.to/2.0/gems/reform/populator A populator for a single property is called once. This example ensures a composer Artist object exists, creating one if it doesn't. ```ruby class AlbumForm < Reform::Form property :composer, populator: -> (model:, **) do model || self.composer= Artist.new end ``` -------------------------------- ### Property Instance with Positional Arguments Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of defining a property's instance logic using positional arguments. This signature is for parsing and includes various context options. ```ruby property :artist, instance: ->(options) do options[:input] options[:fragment] # the parsed fragment options[:doc] # the entire document options[:result] # whatever the former function returned, # usually this is the deserialized object. options[:user_options] # options passed into the parse method (e.g. from_json). options[:index] # index of the currently iterated fragment (only with collection) end ``` -------------------------------- ### View explicit loading order sample Source: https://trailblazer.to/2.0/gems/trailblazer/loader A sample list of files demonstrating the order in which concepts and operations are loaded. ```json [ "app/concepts/navigation/cell.rb", "app/concepts/session/impersonate.rb", "app/concepts/session/operation.rb", "app/concepts/user/operation.rb", "app/concepts/comment/cell/cell.rb", "app/concepts/comment/cell/grid.rb", "app/concepts/comment/operation/create.rb", "app/concepts/api/v1.rb", "app/concepts/thing/callback/default.rb", "app/concepts/thing/callback/upload.rb", "app/concepts/thing/cell.rb", "app/concepts/thing/cell/decorator.rb", "app/concepts/thing/cell/form.rb", "app/concepts/thing/cell/grid.rb", "app/concepts/thing/contract/create.rb", "app/concepts/thing/contract/update.rb", "app/concepts/thing/policy.rb", "app/concepts/thing/signed_in.rb", "app/concepts/thing/operation/create.rb", "app/concepts/thing/operation/delete.rb", "app/concepts/thing/operation/show.rb", "app/concepts/thing/operation/update.rb", "app/concepts/api/v1/comment/representer/show.rb", "app/concepts/api/v1/comment/operation/create.rb", "app/concepts/api/v1/comment/operation/show.rb", "app/concepts/api/v1/thing/representer/create.rb", "app/concepts/api/v1/thing/representer/index.rb", "app/concepts/api/v1/thing/representer/show.rb", "app/concepts/api/v1/thing/operation/create.rb", "app/concepts/api/v1/thing/operation/index.rb", "app/concepts/api/v1/thing/operation/update.rb" ] ``` -------------------------------- ### Namespace operations manually Source: https://trailblazer.to/2.0/gems/trailblazer/loader Example of defining a namespaced operation class. ```ruby module Comment::Operation class Create < Trailblazer::Operation ``` -------------------------------- ### Execute an Activity Source: https://trailblazer.to/2.0/gems/activity/0.2/api.html Runs an activity instance by calling it with initial options. ```ruby my_options = {} last_signal, options, flow_options, _ = activity.( nil, my_options, {} ) ``` -------------------------------- ### Cell Initialization Source: https://trailblazer.to/2.0/gems/cells/api Shows how to manually instantiate a cell, passing a model object. This is helpful in environments where helpers are not available. ```ruby cell = Comment::Cell.new(comment) ``` -------------------------------- ### Accessing Serialized Hash Data Source: https://trailblazer.to/2.0/gems/disposable/api Example of a model with a serialized hash field. ```ruby album = Album.find(1) album.payload #=> { "title"=> "A View To A Kill", "band" => { "name" => "Duran Duran" } } ``` -------------------------------- ### Full Operation with Multiple Representers Source: https://trailblazer.to/2.0/gems/operation/2.0/representer A comprehensive example showing an operation with contract validation, multiple named representers, and a controller action handling success and error states. ```ruby class ErrorsRepresenter < Representable::Decorator include Representable::JSON collection :errors end ``` ```ruby class Create < Trailblazer::Operation extend Contract::DSL extend Representer::DSL contract do property :title validates :title, presence: true end representer :parse do property :title end representer :render do include Roar::JSON::HAL property :id property :title link(:self) { "/songs/#{represented.id}" } end representer :errors, ErrorsRepresenter # explicit reference. step Model( Song, :new ) step Contract::Build() step Contract::Validate( representer: self["representer.parse.class"] ) step Contract::Persist( method: :sync ) end ``` ```ruby def create result = Create.(params, "document" => request.body.read) if result.success? result["representer.render.class"].new(result["model"]).to_json else result["representer.errors.class"].new(result["result.contract.default"]).to_json end end ``` -------------------------------- ### Implement Post Viewing Endpoint Source: https://trailblazer.to/2.0/guides/sinatra/getting-started Set up a Sinatra GET endpoint to present a post using a Trailblazer operation and display it using a cell. Handles post ID parameter for retrieval. ```ruby get "/posts/:id" do op = Post::Update.present(params) Post::Cell::Show.(op.model, url: "/posts").() end ``` -------------------------------- ### Reproduce uninitialized collection error Source: https://trailblazer.to/2.0/gems/reform/populator Example of a crash occurring when a collection is nil during validation. ```ruby class AlbumForm < Reform::Form collection :songs, populate_if_empty: Song do property :title end end album = Album.new form = AlbumForm.new(album) album.songs #=> nil form.songs #=> nil form.validate(songs: [{title: "Friday"}]) #=> NoMethodError: undefined method `original' for nil:NilClass ``` -------------------------------- ### Inspect failure output Source: https://trailblazer.to/2.0/guides/trailblazer/2.0/02-trailblazer-basics Example of a typical RSpec failure message when model attributes are not persisted. ```text Failure/Error: expect(result["model"].title).to eq("Puns: Ode to Joy") # fails! expected: "Puns: Ode to Joy" got: nil ``` -------------------------------- ### Access options via lambda Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api Demonstrates receiving the full options hash in a lambda. ```ruby if: ->(options) { options[:fragment].nil? } ``` -------------------------------- ### Configure a prepopulator Source: https://trailblazer.to/2.0/gems/reform/prepopulator Use the :prepopulator option with a lambda or method name to define logic for initializing form properties. ```ruby class AlbumForm < Reform::Form property :artist, prepopulator: ->(options) { self.artist = Artist.new } do property :name end ``` -------------------------------- ### Validate input for deletion Source: https://trailblazer.to/2.0/gems/reform/populator Example input structure containing a delete flag for a collection item. ```ruby form.validate({ songs: [ {"name"=>"Midnight Rendezvous", "id"=>2, "delete"=>"1"}, {"name"=>"Information Error"} ] }) ``` -------------------------------- ### Install Reform with Dry-validation Source: https://trailblazer.to/2.0/gems/reform Add the required gems to your Gemfile and configure the initializer to use Dry-validation. ```ruby gem "reform" gem "dry-validation" ``` ```ruby require "reform/form/dry" Reform::Form.class_eval do include Reform::Form::Dry end ``` -------------------------------- ### Basic Form Initialization Source: https://trailblazer.to/2.0/gems/formular/bootstrap Initialize a form with a model and URL. This is the fundamental structure for any Formular form. ```ruby form(model.contract, url) do |f| ``` -------------------------------- ### Pass options to prepopulate Source: https://trailblazer.to/2.0/gems/reform/prepopulator Arguments passed to prepopulate! are accessible within the :prepopulator block. ```ruby class AlbumForm < Reform::Form property :title, prepopulator: ->(options) { self.title = options[:def_title] } end ``` ```ruby form.title #=> nil form.prepopulate!(def_title: "Roxanne") form.title #=> "Roxanne" ``` -------------------------------- ### Creating a Model Instance with the Model Macro Source: https://trailblazer.to/2.0/gems/operation/2.0/api Use the `Model` macro to automatically create a new model instance. The instance is then available in `options["model"]` for subsequent steps. ```ruby class Create < Trailblazer::Operation step Model( Song, :new ) # .. end ``` ```ruby result = Create.({}) result["model"] #=> # ``` -------------------------------- ### Configure Property Options Source: https://trailblazer.to/2.0/gems/reform/api Define property types and retrieve configuration metadata using options_for. ```ruby property :title, type: String ``` ```ruby form.options_for(:title) # => {:readable=>true, :coercion_type=>String} ``` -------------------------------- ### Instantiate Objects with :instance Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api Use :instance to manually instantiate the represented object instead of relying on :class. ```ruby property :artist, instance: ->(fragment) do fragment["type"] == "rockstar" ? Rockstar.new : Artist.new end ``` -------------------------------- ### Reform Nilify Coercion Example Source: https://trailblazer.to/2.0/newsletter/2016-march Shows how setting an empty string to a property with `nilify: true` results in `nil`. ```ruby form.id = "" form.id #=> nil ``` -------------------------------- ### Override Preparation with :prepare Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api Use :prepare to override the default object decoration and preparation step. ```ruby property :artist, prepare: ->(represented:,**) { ArtistRepresenter.new(input) } ``` ```ruby property :artist, prepare: ->(represented:,binding:,**) { binding[:extend].new(represented) } ``` -------------------------------- ### Define Form Validation Source: https://trailblazer.to/2.0/gems/reform/api Examples of defining form properties and validations using either dry-validation or ActiveModel syntax. ```ruby class AlbumForm < Reform::Form property :title validation do required(:title).filled end property :artist do property :name validation do required(:name).filled end end end ``` ```ruby class AlbumForm < Reform::Form property :title validates :title, presence: true property :artist do property :name validates :name, presence: true end end ``` -------------------------------- ### Skip Render Condition Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of a `skip_render` lambda that conditionally skips rendering based on options and input name. ```ruby skip_render: lambda { |options| # raise options[:represented].inspect options[:user_options][:skip?] and options[:input].name == “Rancid” ``` -------------------------------- ### View Paths Configuration Source: https://trailblazer.to/2.0/gems/cells/render Demonstrates how to set and append view paths for cells. ```APIDOC ## View Paths Configuration ### Description Every cell class can have multiple view paths. This section explains how to set and append view paths using the `::view_paths` method. ### Method Class method assignment and append. ### Endpoint N/A (Class-level configuration) ### Parameters N/A ### Request Example ```ruby class Cell::ViewModel self.view_paths = ["app/cells"] end class Shopify::CartCell self.view_paths << "/var/shopify/app/cells" end ``` ### Response N/A (Configuration) ### Inspecting View Paths #### Description Use the `::prefixes` class method to inspect the directory lookup list for a cell. #### Method Class method inspection. #### Endpoint N/A (Class-level inspection) #### Parameters N/A #### Request Example ```ruby puts Shopify::CartCell.prefixes #=> ["app/cells/shopify/cart", "/var/shopify/app/cells/shopify/cart"] ``` #### Response Example N/A (Output to console) ``` -------------------------------- ### Defining a Cell Class Source: https://trailblazer.to/2.0/gems/cells/trailblazer Example of a cell class definition where the render method automatically maps to the corresponding view. ```ruby module Comment::Cell # namespace class New < Trailblazer::Cell # class def show render # renders app/concepts/comment/view/new.slim. end end end ``` -------------------------------- ### Populator with a proc constant Source: https://trailblazer.to/2.0/gems/reform/populator This Ruby code demonstrates using a pre-defined proc constant as a populator. This can help organize populator logic, especially when it's reusable or complex. ```ruby ArtistPopulator = ->(options) { .. } property :artist, populator: ArtistPopulator ``` -------------------------------- ### Sparse Fieldsets Example Output Source: https://trailblazer.to/2.0/gems/roar/jsonapi This JSON output demonstrates how sparse fieldsets limit the attributes rendered for the primary data to only 'title'. ```json "data": { "type": "articles", "id": "1", "attributes": {"title": "My Article"} } ``` -------------------------------- ### Non-Rails Gemfile Configuration Source: https://trailblazer.to/2.0/guides/getting-started Gemfile setup for non-Rails projects that do not use Active* components, including Trailblazer, loader, Reform, and dry-validation. ```ruby gem "trailblazer" gem "trailblazer-loader" # optional, if you want us to load your concepts. gem "reform", ">= 2.2.0" gem "dry-validation", ">= 0.8.0" # optional, in case you want Cells. gem "trailblazer-cells" gem "cells-erb" # Or cells-haml, cells-slim, cells-hamlit. ``` -------------------------------- ### Rspec Cell Testing Setup Source: https://trailblazer.to/2.0/gems/cells/testing Use the `rspec-cells` gem for Rspec integration. The `#cell` and `#concept` builders can be used directly in your specs. ```ruby gem "rspec-cells" ``` ```ruby describe SongCell, type: :cell do subject { cell(:song, Song.new).(:show) } it { expect(subject).to have_content "Song#show" } end ``` -------------------------------- ### Define an Activity for Tracing Source: https://trailblazer.to/2.0/gems/activity/0.2/flow Defines a sample activity structure using `Activity.from_hash` which will be used for tracing. This sets up the flow between different tasks. ```ruby activity = Activity.from_hash do |start, _end| { start => { Activity::Right => Blog::Write }, Blog::Write => { Activity::Right => Blog::SpellCheck }, Blog::SpellCheck => { Activity::Right => Blog::Publish, Activity::Left => Blog::Correct }, Blog::Correct => { Activity::Right => Blog::SpellCheck }, Blog::Publish => { Activity::Right => _end } } end ``` -------------------------------- ### Reform Integer Coercion Example Source: https://trailblazer.to/2.0/newsletter/2016-march Demonstrates how Reform coerces a string value to an integer when the `:type` option is set to `Types::Form::Int`. ```ruby form.id = "1" form.id #=> 1 ``` -------------------------------- ### Inherit Engine Cell View Paths Source: https://trailblazer.to/2.0/gems/cells/rails Demonstrates inheriting view path configuration from a base engine cell. ```ruby module MyEngine class Song::Cell < Cell # inherits from MyEngine::Cell ``` -------------------------------- ### Cell Initialization and Model Source: https://trailblazer.to/2.0/gems/cells/api Details how to initialize a cell instance, passing in a model object that can be accessed within the cell. ```APIDOC ## Cell Initialization and Model ### Description Cells can be instantiated manually, typically passing a model object which is then accessible via the `model` reader. ### Method N/A (Instantiation) ### Endpoint N/A ### Parameters N/A ### Request Example ```ruby # Instantiate with a model cell = Comment::Cell.new(comment) # Access the model within the cell class CommentCell < Cell::ViewModel def show model.rude? ? "Offensive content." : render end end ``` ### Response N/A ``` -------------------------------- ### Rendered XML with Namespaces Source: https://trailblazer.to/2.0/gems/representable/3.0/xml Example of an XML document rendered with defined namespaces. The top representer includes all namespace definitions as `xmlns` attributes. ```xml %{ 666 Fowler typed Frau Java 1991 } ``` -------------------------------- ### Manual Cell Invocation Source: https://trailblazer.to/2.0/gems/cells/api Demonstrates how to manually instantiate and invoke a cell, useful in environments where helpers are not readily available. ```APIDOC ## Manual Cell Invocation ### Description This shows how to manually create a cell instance and then invoke its rendering state. ### Method N/A (Instantiation and Invocation) ### Endpoint N/A ### Parameters N/A ### Request Example ```ruby # Instantiate the cell with a model cell = Comment::Cell.new(comment) # Invoke the default 'show' state cell.() #=> "I don't like templates!" ``` ### Response - String: The rendered output of the cell's default state. ``` -------------------------------- ### Implement steps as methods, lambdas, or callables Source: https://trailblazer.to/2.0/gems/operation/2.0/api Steps can be defined as instance methods, procs, or classes that implement the Callable interface. ```ruby class Create < Trailblazer::Operation step :model! def model!(options, **) options["model"] = Song.new end end ``` ```ruby class Create < Trailblazer::Operation step ->(options, **) { options["model"] = Song.new } end ``` ```ruby class MyModel extend Uber::Callable def self.call(options, **) options["model"] = Song.new end end ``` ```ruby class Create < Trailblazer::Operation step MyModel end ``` -------------------------------- ### Accessing Unnested Property Source: https://trailblazer.to/2.0/gems/disposable/api After unnesting, the property can be accessed directly on the twin instance. This example demonstrates reading and writing to the unnested `email` property. ```ruby album = Album.find(1) twin = AlbumTwin.new(album) twin.email #=> "duran@duran.to" twin.email = "duran@duran.com" ``` -------------------------------- ### Define Complex Role Collection for Select Options Source: https://trailblazer.to/2.0/gems/formular/bootstrap An example of a nested array structure for populating select options, allowing for grouped choices. ```ruby complex_role = [['Team', [['England', 'e'], %w(Italy i),['Germany', 'g']]],['Roles', [['Fullback', 0], ['Hooker', 1], ['Wing', 2]]]] ``` -------------------------------- ### Custom object creation with populate_if_empty Source: https://trailblazer.to/2.0/gems/reform/populator This Ruby code shows a custom populator using a lambda with :populate_if_empty. It demonstrates how to find an existing Song by name or create a new one if no match is found, leveraging data from the incoming fragment. ```ruby class AlbumForm < Reform::Form collection :songs, populate_if_empty: ->(fragment:, **) do Song.find_by(name: fragment["name"]) or Song.new end ``` -------------------------------- ### Perform basic serialization and parsing Source: https://trailblazer.to/2.0/gems/roar/jsonapi Entry points for handling singular models and collections using the representer. ```ruby SongsRepresenter.new(Song.find(1)).to_json SongsRepresenter.new(Song.new).from_json("..") ``` ```ruby SongsRepresenter.for_collection.new([Song.find(1), Song.find(2)]).to_json SongsRepresenter.for_collection.new([Song.new, Song.new]).from_json("..") ``` -------------------------------- ### Explicit-Singular Directory Structure Source: https://trailblazer.to/2.0/gems/trailblazer/loader Demonstrates the Explicit-Singular layout where each abstraction layer is a directory with individual files for each class. ```ruby app ├── concepts │ ├── comment │ │ ├── contract │ │ │ ├── create.rb │ │ │ └── update.rb │ │ ├── cell │ │ │ └── form.rb │ │ ├── operation │ │ │ ├── create.rb │ │ │ └── update.rb │ │ └── views │ │ ├── grid.haml │ │ └── show.haml ``` -------------------------------- ### Define Instance Methods for Views Source: https://trailblazer.to/2.0/gems/cells/api Use properties and instance methods to keep views logic-less. ```haml %h1 Show comment = body = author_link ``` ```ruby class CommentCell < Cell::ViewModel property :body # creates #body reader. def author_link url_for model.author.name, model.author end end ``` -------------------------------- ### Include ActiveRecord Module Manually Source: https://trailblazer.to/2.0/gems/reform/rails In some Rails/AR setups, you may need to manually include the Reform::Form::ActiveRecord module for ActiveRecord-specific features. ```ruby class SongForm < Reform::Form include Reform::Form::ActiveRecord ``` -------------------------------- ### Capybara with Minitest::Spec Setup Source: https://trailblazer.to/2.0/gems/cells/testing In non-Rails environments, use `capybara_minitest_spec`. Include `Cell::Testing` and set `Cell::Testing.capybara = true` in your `test_helper.rb`. ```ruby group :test do gem "capybara_minitest_spec" end ``` ```ruby require "capybara_minitest_spec" Cell::Testing.capybara = true ``` ```ruby class NavigationCellTest < Minitest::Spec include Cell::Testing it "renders avatar when user provided" do html = cell(Pro::Cell::Navigation, user).() html.must_have_css "#avatar-signed-in" html.to_s.must_match "Signed in: nick@trb.to" end ``` -------------------------------- ### Basic Attribute Assertions Source: https://trailblazer.to/2.0/gems/trailblazer/2.0/test This demonstrates the equivalent of `assert_exposes` using basic `assert_equal` for comparison. Use `assert_exposes` for conciseness. ```ruby assert_equal "Timebomb", model.title assert_equal "Rancid", model.band ``` -------------------------------- ### Application Policy for Access Control Source: https://trailblazer.to/2.0 Policies are used within operations to grant or deny access to functionality. This example shows a basic create policy. ```ruby class Application::Policy < Pundit::Policy def create? user.can_create?(model) end end ``` -------------------------------- ### Pass User Options Directly (Deprecated) Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Demonstrates the deprecated method of passing dynamic options directly to `to_hash`. This approach is no longer recommended. ```ruby decorator.to_hash(is_admin: true) ``` -------------------------------- ### Property Instance with Pass Options (Deprecated) Source: https://trailblazer.to/2.0/gems/representable/upgrading-guide Example of using the deprecated `:pass_options` option to access represented object. This functionality is now available through generic options. ```ruby property :artist, pass_options: true, instance: ->(fragment, options) { options.represented } ``` -------------------------------- ### Rendering Partials Source: https://trailblazer.to/2.0/gems/cells/render Explains how to render global partials from Cells using the `:partial` option. ```APIDOC ## Rendering Partials ### Description This section covers how to render global partials from Cells, even though it's considered a taboo. It requires using the `:partial` option with a path relative to the cell's view path. ### Method Instance method with `render` and `:partial` option. ### Endpoint N/A (Instance method rendering) ### Parameters #### Request Body - **partial** (string) - Required - Path to the partial relative to the cell's view path. ### Request Example ```ruby class SongCell < Cell::ViewModel include Partial def show render partial: "../views/shared/sidebar.html" end end ``` ### Response N/A (Rendering output) ### Notes Cells will automatically add the format and the underscore prefix to the partial name, resulting in a lookup for `"../views/shared/_sidebar.html.erb"`. ``` -------------------------------- ### Show Method Source: https://trailblazer.to/2.0/gems/cells/api Explains the purpose and usage of the `#show` method within a cell, which is conventionally the public method responsible for rendering. ```APIDOC ## Show Method ### Description The `#show` method is the conventional public interface for a cell. Its return value is what gets rendered. ### Method N/A (Instance Method) ### Endpoint N/A ### Parameters N/A ### Request Example ```ruby def show "I don't like templates!" end ``` ### Response - String: The rendered HTML fragment or a custom string. ``` -------------------------------- ### Defining Properties with Options Source: https://trailblazer.to/2.0/gems/representable/3.0/function-api How to define properties in a representer and apply static or dynamic options. ```APIDOC ## property :name, options ### Description Defines a property on the representer. Options can be static values or dynamic lambdas that receive an options hash. ### Parameters - **name** (symbol) - Required - The name of the property. - **options** (hash) - Optional - Configuration options like :as, :if, :getter, :setter, etc. ### Request Example ```ruby property :id, default: "n/a" property :id, if: ->(options) { options[:fragment].nil? } ``` ``` -------------------------------- ### Configure Trailblazer base controller Source: https://trailblazer.to/2.0/gems/trailblazer/2.0/rails Customize the base controller class that Trailblazer-rails extends by setting `trailblazer.application_controller` in an initializer. The value should be a string that gets constantized. ```ruby # config/initializers/trailblazer.rb Rails.application.config.trailblazer.application_controller = "MyApp::BaseController" ``` -------------------------------- ### Define Operation with Simple Lambda Step Source: https://trailblazer.to/2.0/gems/operation/2.0/api A basic operation that multiplies two factors and stores the result in the options hash. This serves as a nested operation example. ```ruby class Multiplier < Trailblazer::Operation step ->(options, x:, y:, **) { options["product"] = x*y } end ``` -------------------------------- ### Render Form with Various Input Types and Options Source: https://trailblazer.to/2.0/gems/formular/bootstrap Demonstrates various input types (hidden, email, password, file, color, number) and options like `value`, `disabled`, and `hint`. Ensure `enctype: 'multipart/form-data'` is set for file uploads. ```ruby = form(input_options, url, enctype: 'multipart/form-data', builder: :bootstrap3) do |f| = f.input :id, type: 'hidden', value: "some_id" = f.input :email, type: 'email', label: "Email" = f.input :password, type: 'password', label: "Password" = f.input :image, type: 'file', label: "Image" = f.input :background_color, type: 'color', label: "Background Colour", hint: "Select the background colour for your image!" = f.input :number, type: 'number', label:"Number", disabled: true, value: '5' = f.submit content: "Submit!", class: ['btn-lg'] ``` -------------------------------- ### Parse XML with Namespaces Source: https://trailblazer.to/2.0/gems/representable/3.0/xml Namespaces apply during XML parsing. Only prefixed tags defined in the representer will be considered. This example shows parsing and accessing a namespaced property. ```ruby Library.new(lib).from_xml(%{ ib:book id="1"> 666 Fowler typed Frau Java Mr. Ruby Dr. Elixir 1991 lib:book> b:library>} ) ``` ```ruby lib.book.character[0].name #=> "Frau Java" ``` -------------------------------- ### Access Operation Options Source: https://trailblazer.to/2.0/guides/trailblazer/2.0/01-operation-basics Shows how to access input parameters from the options hash within a step. ```ruby def how_are_you?(options, *) # ... options["params"] #=> { happy: "yes" } end ``` -------------------------------- ### Custom object creation with instance method Source: https://trailblazer.to/2.0/gems/reform/populator This Ruby code defines a custom populator using an instance method reference with :populate_if_empty. The 'populate_songs!' method handles finding an existing Song or creating a new one based on the fragment data. ```ruby class AlbumForm < Reform::Form collection :songs, populate_if_empty: :populate_songs! do property :name end def populate_songs!(fragment:, **) Song.find_by(name: fragment["name"]) or Song.new end ``` -------------------------------- ### Render Object to JSON using Decorator Source: https://trailblazer.to/2.0/gems/representable/3.0/api Instantiate a decorator with an object and call `to_json` to get the JSON representation. Ensure the object has the properties defined in the representer. ```ruby # Given a Struct like this Song = Struct.new(:id, :title) #=> Song # You can instantiate it with the following song = Song.new(1, "Fallout") #=> # # This object doesn't know how to represent itself in JSON song.to_json #=> NoMethodError: undefined method `to_json' # But you can decorate it with the above defined representer song_representer = SongRepresenter.new(song) # Relax and let the representer do its job song_representer.to_json #=> {"id":1,"title":"Fallout"} ``` -------------------------------- ### Manage State with the Result Object Source: https://trailblazer.to/2.0/gems/operation/2.0/api The result object (options) is passed between steps to read and write state. Namespacing keys with a prefix like 'my.' is recommended. ```ruby class Song::Create < Trailblazer::Operation step :model! step :assign! step :validate! def model!(options, current_user:, **) options["model"] = Song.new options["model"].created_by = current_user end def assign!(*, params:, model:, **) model.title= params[:title] end def validate!(options, model:, **) options["result.validate"] = ( model.created_by && model.title ) end end ``` ```ruby def validate!(options, model:, **) options["result.validate"] = ( model.created_by && model.title ) end ``` -------------------------------- ### Instantiate Contract with Contract::Build Source: https://trailblazer.to/2.0/gems/operation/2.0/contract Use Contract::Build to instantiate a contract, passing the model from options["model"] to the contract's constructor. The contract is then saved in options["contract.default"]. ```ruby class Song::New < Trailblazer::Operation step Model( Song, :new ) step Contract::Build( constant: Song::Contract::Create ) end ``` ```ruby result = Song::New.() result["model"] #=> # result["contract.default"] #=> #> ``` -------------------------------- ### Access Twin Properties Source: https://trailblazer.to/2.0/gems/disposable/api Twin properties can be accessed like regular object attributes. This example shows reading a top-level property and an optional property passed during initialization. ```ruby twin.title #=> "Nice Try" twin.playable? #=> true ``` -------------------------------- ### Cell Options Source: https://trailblazer.to/2.0/gems/cells/api Explains how to pass arbitrary options, such as the current user, to a cell during instantiation and how to access them. ```APIDOC ## Cell Options ### Description Arbitrary options can be passed to a cell during initialization, alongside the model. These options are accessible via the `options` reader. ### Method N/A (Instantiation) ### Endpoint N/A ### Parameters N/A ### Request Example ```ruby # Instantiate with model and options cell = Comment::Cell.new(comment, current_user: current_user) # Access options within the cell class CommentCell < Cell::ViewModel def show options[:current_user] ? render : "Not logged in!" end end ``` ### Response N/A ``` -------------------------------- ### Representing Specific Properties with :include Source: https://trailblazer.to/2.0/gems/representable/3.0/api Use the :include option to specify which properties should be represented. All other properties will be skipped. ```ruby song_representer.to_json(include: [:id]) #=> {"id":1} ``` -------------------------------- ### Default Show Method Source: https://trailblazer.to/2.0/gems/cells/trailblazer The recommended way to define a cell without explicit show method implementation. ```ruby module Comment::Cell class New < Trailblazer::Cell end end ``` -------------------------------- ### Assert Object Attributes with Custom Reader Source: https://trailblazer.to/2.0/gems/trailblazer/2.0/test Uses `assert_exposes` with a custom `:reader` option (e.g., `:get`) to test objects that expose attributes via a specific method. ```ruby it do assert_exposes model, { title: "Timebomb", band: "Rancid" }, reader: :get end ``` -------------------------------- ### Define Step Arguments with Procs and Methods Source: https://trailblazer.to/2.0/gems/operation/2.0/api Steps receive the context object as a positional argument and runtime data as keyword arguments. Use ** to ignore unspecified keyword arguments. ```ruby class Create < Trailblazer::Operation step ->(options, params:, current_user:, **) { } end ``` ```ruby class Create < Trailblazer::Operation step :setup! def setup!(options, params:, current_user:, **) # ... end end ``` -------------------------------- ### Write Values to Twin (Not Model) Source: https://trailblazer.to/2.0/gems/disposable/api Writers modify values directly on the twin instance. These changes are not immediately propagated to the underlying model. This example shows setting a title on the twin. ```ruby twin.title = "Skamobile" twin.title #=> "Skamobile" album.title #=> "Nice Try" ``` -------------------------------- ### Factory with `let` Source: https://trailblazer.to/2.0/gems/trailblazer/2.0/test Combines the `factory` helper with `let` for defining reusable model instances in tests. ```ruby let(:song) { factory( Song::Create, { title: "Timebomb", band: "Rancid" } ) } ``` -------------------------------- ### Initialize Trailblazer Loader Source: https://trailblazer.to/2.0/gems/trailblazer/loader Basic initialization of the loader with a block to handle file requiring. ```ruby Trailblazer::Loader.new.() { |file| require_dependency(File.join(Rails.app.root, file)) } ``` -------------------------------- ### Syncing Unnested Property Source: https://trailblazer.to/2.0/gems/disposable/api When `sync` is called, only the nested structure is considered for updating the model. This example shows how the updated `email` on the twin is written back to the nested `artist.email` on the model. ```ruby twin.sync album.artist.email #=> "duran@duran.com" ``` -------------------------------- ### Trace an Activity's Execution Source: https://trailblazer.to/2.0/gems/activity/0.2/flow Uses the `Trailblazer::Activity::Trace` module to trace the execution of a defined activity. This setup allows for monitoring the activity's path and data. ```ruby stack, _ = Trailblazer::Activity::Trace.( activity, [ { content: "Let's start writing" } ] ) ``` -------------------------------- ### Use Model Macro for Creation Source: https://trailblazer.to/2.0/guides/trailblazer/2.0/02-trailblazer-basics Replaces manual model instantiation with the Model macro to simplify operation logic. ```ruby class BlogPost::Create < Trailblazer::Operation step Policy::Guard( :authorize! ) step Model( BlogPost, :new ) step :persist! step :notify! def authorize!(options, current_user:, **) current_user.signed_in? end def persist!(options, params:, model:, **) model.update_attributes(params[:blog_post]) model.save end def notify!(options, current_user:, model:, **) BlogPost::Notification.(current_user, model) end end ``` -------------------------------- ### Compound-Singular Directory Structure Source: https://trailblazer.to/2.0/gems/trailblazer/loader Illustrates the Compound-Singular layout where each abstraction layer has a single file per concept. ```ruby app ├── concepts │ ├── comment │ │ ├── callback.rb │ │ ├── cell.rb │ │ ├── contract.rb │ │ ├── operation.rb │ │ ├── policy.rb │ │ └── views │ │ ├── grid.haml │ │ └── show.haml ``` -------------------------------- ### Populator with a proc Source: https://trailblazer.to/2.0/gems/reform/populator This Ruby code shows how to define a populator using a lambda (proc) for a property. The proc receives options and is responsible for handling the deserialization logic. ```ruby property :artist, populator: ->(options) { .. } # proc ```