{"id":13878697,"url":"https://github.com/simple-and-powerful/act-form","last_synced_at":"2026-01-10T03:57:16.864Z","repository":{"id":56842027,"uuid":"76338801","full_name":"simple-and-powerful/act-form","owner":"simple-and-powerful","description":"The simple way to create form objects or command/service objects with ActiveModel","archived":false,"fork":false,"pushed_at":"2024-06-25T11:01:22.000Z","size":58,"stargazers_count":31,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-16T13:09:05.912Z","etag":null,"topics":["activemodel","command-object","form-model","form-object","rails","ruby","service-object","validation"],"latest_commit_sha":null,"homepage":"https://github.com/simple-and-powerful/act-form","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/simple-and-powerful.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-13T08:30:09.000Z","updated_at":"2024-09-13T08:59:48.000Z","dependencies_parsed_at":"2024-10-02T14:50:41.913Z","dependency_job_id":"bf53485e-a458-4394-b26d-d03e1771bb67","html_url":"https://github.com/simple-and-powerful/act-form","commit_stats":{"total_commits":37,"total_committers":3,"mean_commits":"12.333333333333334","dds":0.08108108108108103,"last_synced_commit":"7c699e833d9a90ef8361d1bb39f5eedd0adeeb41"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simple-and-powerful%2Fact-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simple-and-powerful%2Fact-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simple-and-powerful%2Fact-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simple-and-powerful%2Fact-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simple-and-powerful","download_url":"https://codeload.github.com/simple-and-powerful/act-form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236261785,"owners_count":19120773,"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","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":["activemodel","command-object","form-model","form-object","rails","ruby","service-object","validation"],"created_at":"2024-08-06T08:01:57.035Z","updated_at":"2025-10-12T18:30:20.445Z","avatar_url":"https://github.com/simple-and-powerful.png","language":"Ruby","readme":"# ActForm\n\nActForm is the gem that provide a simple way to create `form object` or `command object` or `service object`, it only depends on `activemodel \u003e= 5` and provides few api.\n\n## About v0.5.0\n\nWith the power of `dry-schema`, ActForm now can support all the features of `dry-schema`, like:\n\n```ruby\nclass UserForm \u003c ActForm::Base\n  params do\n    required(:name).filled.desc('Name')\n    optional(:age).value(:integer).desc('Age')\n    optional(:address).desc('Address')\n    optional(:nickname).default('nick').desc('Nick')\n    # below will support in the future\n    # attribute :desc, default: -\u003e{ 'desc' }\n  end\nend\n```\n\nAdd we can integrate with `grape` easyly.\n\n```ruby\nmodule WorkWithGrapeSpec\n  class API \u003c Grape::API\n    format :json\n\n    contract UserForm.contract\n    get '/foo' do\n      'hello world'\n    end\n\n    contract UserForm.contract do\n      required(:desc).filled\n    end\n    get '/bar' do\n      'hello world'\n    end\n  end\nend\n```\n\n## Usage\n\n#### API - `attribute`\n\n```ruby\nclass UserForm \u003c ActForm::Base\n  attribute :name, required: true\n  attribute :age,  type: :integer\n  attribute :address\n  attribute :nickname, default: 'nick'\n  attribute :desc, default: -\u003e{ 'desc' }\nend\n\nform = UserForm.new(name: 'su', age: '18', address: 'somewhere')\nform.name # =\u003e 'su'\nform.age # =\u003e 18\nform.address # =\u003e 'somewhere'\nform.nickname # =\u003e 'nick'\nform.desc # =\u003e 'desc'\n# override default\nform.nickname = 'hello'\nform.nickname # =\u003e 'hello'\n\n# required\nform = UserForm.new(age: '18', address: 'somewhere')\nform.valid? # =\u003e false\nform.errors.full_messages # =\u003e [\"Name require a value\"]\n```\n\n#### Difference between `required` and `validates_presence_of`\n`required` will run before the validation, and it will cancel other validations if return false.\n\n### form object\n\n#### API - `valid?`\nCompliant with the active model api\n```ruby\nclass PhoneForm \u003c ActForm::Base\n  attribute :phone\n  \n  validates_format_of :phone, with: /\\A\\d{11}\\z/i\nend\n\nform = PhoneForm.new\nform.valid? # =\u003e false\nform.errors.full_messages # =\u003e [\"Phone is invalid\"]\n\nPhoneForm.new(phone: '12345678901').valid? # =\u003e true\n```\n\n#### API - `sync`\nsync only copy attributes to target, will not trigger validate\n```ruby\ntarget = Class.new do\n  attr_accessor :phone\nend.new\n\nform = PhoneForm.new(phone: '12345678901')\nform.sync(target)\ntarget.phone # =\u003e '12345678901'\n```\n\n#### API - `save`\nsync to the target and call the save method when passed the validation\n```ruby\ntarget = Class.new do\n  attr_accessor :phone\n  attr_reader :saved\n  \n  def save\n    @saved = true\n  end\nend.new\n\nform = PhoneForm.new(phone: '12345678901')\nform.save(target) # same as form.sync(target) and target.save\ntarget.phone # =\u003e '12345678901'\ntarget.saved # =\u003e true\nform.persisted? # =\u003e true\n```\n\n#### API - `init_by`\n`init_by` will copy attributes form target to the form, and set default target.\n```ruby\ntarget = Class.new do\n  attr_accessor :phone\n  attr_reader :saved\n  \n  def save\n    @saved = true\n  end\nend.new\n\ntarget.phone = '12345678901'\n\nform = PhoneForm.new\nform.init_by(target)\nform.phone # =\u003e '12345678901'\nform.save # =\u003e true\ntarget.saved # =\u003e true\n```\n\n#### API - `combine`\nform can combine to other forms\n```ruby\nclass PhoneForm \u003c ActForm::Base\n  attribute :phone\n  validates_format_of :phone, with: /\\A\\d{11}\\z/i\nend\n\nclass EmailForm \u003c ActForm::Base\n  attribute :email\n  \n  validate :check_email\n  \n  def check_email\n    errors.add(:email, :blank) if email.blank?\n  end\nend\n\nclass UserForm \u003c ActForm::Base\n  combine PhoneForm, EmailForm\nend\n\nclass AdminForm \u003c ActForm::Base\n  combine PhoneForm\nend\n\nuser_form = UserForm.new\nuser_form.valid?\nuser_form.errors.full_messages # =\u003e [\"Phone is invalid\", \"Email can't be blank\"]\nUserForm.new(phone: '12345678901', email: '1').valid? # =\u003e true\nadmin_form = AdminForm.new\nadmin_form.valid?\nadmin_form.errors.full_messages # =\u003e [\"Phone is invalid\"]\nAdminForm.new(phone: '12345678901').valid? # =\u003e true\n```\n\n### command/service object\n\nCommand object almost like form object. Command object can't init by `new`, and it has some new features.\n\n#### API - `perform`, `run`, `success?`, `failure?`, `setup`\n\ncommand object must respond to `perform` method.\n\n```ruby\nclass CreateUserCommand \u003c ActForm::Command\n  combine UserForm\n\n  # Do some pre-inialize actions.\n  setup do\n    @name = 'foo'\n  end\n  \n  def perform\n    attributes[:name] = @name\n    User.create(attributes)\n  end\nend\n\nCreateUserCommand.new \n# =\u003e NoMethodError: private method `new' called for CreateUserCommand:Class \n\ncommand = CreateUserCommand.run(phone: '12345678901')\nif command.success?\n  @user = command.result\n  # do something...\nelse\n  command.errors.full_messages # =\u003e [\"Email can't be blank\"]\n  # do something...\nend\n```\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'act_form'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install act_form\n\n## Development\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n### Unit Tests\n\n    $ bundle exec rake test\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/simple-and-powerful/act_form. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimple-and-powerful%2Fact-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimple-and-powerful%2Fact-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimple-and-powerful%2Fact-form/lists"}