{"id":30110298,"url":"https://github.com/animikii/makwa","last_synced_at":"2025-08-10T04:43:33.090Z","repository":{"id":40259125,"uuid":"409646890","full_name":"animikii/makwa","owner":"animikii","description":"Interactions for Ruby on Rails.","archived":false,"fork":false,"pushed_at":"2025-01-05T20:28:22.000Z","size":158,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-07-28T02:54:55.218Z","etag":null,"topics":["ruby","ruby-on-rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/animikii.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-23T15:29:18.000Z","updated_at":"2025-01-05T20:28:26.000Z","dependencies_parsed_at":"2023-01-22T11:20:28.274Z","dependency_job_id":null,"html_url":"https://github.com/animikii/makwa","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/animikii/makwa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/animikii%2Fmakwa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/animikii%2Fmakwa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/animikii%2Fmakwa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/animikii%2Fmakwa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/animikii","download_url":"https://codeload.github.com/animikii/makwa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/animikii%2Fmakwa/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269677515,"owners_count":24457858,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","ruby-on-rails"],"created_at":"2025-08-10T04:43:29.947Z","updated_at":"2025-08-10T04:43:33.085Z","avatar_url":"https://github.com/animikii.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Makwa\n\nMakwa is an extension of the [ActiveInteraction](https://github.com/AaronLasseigne/active_interaction) gem, bringing interactions to Ruby on Rails apps.\n\n\u003e ActiveInteraction manages application-specific business logic. It's an implementation of service objects designed to blend seamlessly into Rails. It also helps you write safer code by validating that your inputs conform to your expectations. If ActiveModel deals with your nouns, then ActiveInteraction handles your verbs.\n\n\u003cp align=\"right\"\u003eReadme for ActiveInteraction.\u003c/p\u003e\n\nMakwa improves the ergonomics around mutating ActiveRecord instances.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem \"makwa\"\n```\n\nAnd then execute:\n\n```shell\n$ bundle install\n```\n\nOr install it yourself as:\n\n```shell\n$ gem install makwa\n```\n\nMakwa extends the ActiveInteraction gem and will install it automatically as a dependency.\n\nMakwa is compatible with Ruby 2.7 or greater and Rails 5 or greater.\n\n## What does Makwa add to ActiveInteraction?\n\nPlease read through the [ActiveInteraction Readme](https://github.com/AaronLasseigne/active_interaction) first and then come back here to see what Makwa adds to ActiveInteraction:\n\n### ReturningInteraction\n\nReturningInteractions are a special kind of interaction, optimized for usage with Rails forms:\n\nThe basic approach of ActiveInteraction (AI) when rendering ActiveRecord model forms is to pass an AI instance to the form. That approach works great for simple mutations of ActiveRecord instances. However, for this to work, the AI class has to implement all methods required for rendering your forms. That can get tricky when you need to traverse associations, or call complex decorators on your models. This approach also fails if the interaction's `#execute` method is never run because the input validations fail.\n\nReturningInteraction (RI) chooses a different approach: It accepts the to-be-mutated ActiveRecord instance as an input argument and is guaranteed to return that instance, no matter if the interaction outcome is successful or not. The RI will merge all errors that occurred during execution to the returned ActiveRecord instance. This allows you to pass the actual ActiveRecord instance to your form, and you don't have to implement all methods required for the form to be rendered.\n\nLet's look at some example code to see the difference:\n\nThe ActiveInteraction way\n\n```ruby\n# app/controllers/users_controller.rb\nclass UsersController \u003c ApplicationController\n  def new\n    @user = User.new\n  end\n\n  def create\n    outcome = Users::Create.run(\n      params.fetch(:user, {})\n    )\n\n    if outcome.valid?\n      redirect_to(outcome.result)\n    else\n      @user = outcome\n      render(:new)\n    end\n  end\nend\n\n# app/interactions/users/create.rb\nmodule Users\n  class Create \u003c ApplicationInteraction\n    string :first_name\n    string :last_name\n    array :role_ids, default: []\n\n    def execute\n      user = User.new(inputs)\n      errors.merge!(user.errors) unless user.save\n      user\n    end\n\n    def to_model\n      User.new\n    end\n  end\nend\n```\n\nThe Makwa way\n\n```ruby\n# app/controllers/users_controller.rb\nclass UsersController \u003c ApplicationController\n  def new\n    @user = User.new\n  end\n\n  def create\n    # Differences: Pass in the `:user` input and call `#run_returning!` instead of `#run`.\n    @user = Users::Create.run_returning!(\n      {user: User.new}.merge(params.fetch(:user, {}))\n    )\n\n    if @user.errors_empty?\n      redirect_to(@user)\n    else\n      render(:new)\n    end\n  end\nend\n\n# app/interactions/users/create.rb\nmodule Users\n  class Create \u003c ApplicationReturningInteraction\n    returning :user # This is different from AI: Specifies which input will be returned.\n\n    string :first_name\n    string :last_name\n    string :email\n    record :user\n\n    def execute_returning # Notice: Method is called `execute_returning`, not `execute`!\n      user.update(inputs.except(:user))\n      # No need to merge any errors. This will be done automatically by Makwa\n      return_if_errors!\n\n      compose(\n        Infrastructure::SendEmail,\n        recipient_email: user.email,\n        subject: \"Welcome to Makwa\",\n        body: \"Lorem ipsum...\"\n      )\n      # No need for an explicit return of user, also done by Makwa\n      # (via `returning` input filter).\n    end\n\n    # No need to implement the `#to_model` method and any other methods required to\n    # render your forms.\n  end\nend\n```\n\n### Other improvements\n\nMakwa offers **safe ways to check for errors**. Instead of `#valid?` or `#invalid?` use `#errors_empty?` or `#errors_any?`. Rails' `#valid?` method is a destructive method that will clear all errors and re-run validations. This will eradicate any errors you added in the body of the `#execute` or `#execute_returning` methods.\n\nMakwa offers a simple way to **exit early** from the interaction. Use `#return_if_errors!` at any point in the `#execute` method if errors make it impossible to continue execution of the interaction.\n\nMakwa offers **detailed logging** around interaction invocations (with inputs) and outcomes (with errors):\n\n```\nExecuting interaction Users::SendWelcomeEmail (id#1234567)\n ↳ called from Users::Create (id#7654321)\n ↳ inputs: {first_name: \"Giselher\", last_name: \"Wulla\"} (id#7654321)\n # ... execute interaction\n ↳ outcome: failed (id#7654321)\n ↳ errors: \"Email is missing\" (id#7654321)\n```\n\nTo enable debug logging just define this method in your `ApplicationInteraction`:\n\n```ruby\ndef debug(txt)\n  puts indent + txt\nend\n```\n\n### Further reading\n\n* [Usage](doc/usage_examples.md): More complex examples and conventions.\n* [About interactions](doc/about_interactions.md): Motivation, when to use them.\n* [Features and design considerations](doc/features_and_design_considerations.md)\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nWe have [instructions for releasing a new version](doc/how_to_release_new_version.md).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/animikii/makwa.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanimikii%2Fmakwa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanimikii%2Fmakwa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanimikii%2Fmakwa/lists"}