{"id":16486786,"url":"https://github.com/rstankov/miniform","last_synced_at":"2025-03-15T11:33:17.420Z","repository":{"id":27694416,"uuid":"31181059","full_name":"RStankov/MiniForm","owner":"RStankov","description":"Sugar around ActiveModel::Model","archived":false,"fork":false,"pushed_at":"2024-04-21T19:48:10.000Z","size":64,"stargazers_count":30,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-27T01:11:09.450Z","etag":null,"topics":["activemodel","form","gem","ruby"],"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/RStankov.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-02-22T21:18:36.000Z","updated_at":"2024-10-25T02:04:06.000Z","dependencies_parsed_at":"2024-10-11T13:30:31.893Z","dependency_job_id":"ce831bff-d972-4667-9c82-f64eeb6bfb18","html_url":"https://github.com/RStankov/MiniForm","commit_stats":{"total_commits":85,"total_committers":5,"mean_commits":17.0,"dds":"0.14117647058823535","last_synced_commit":"85a13faddf723048b9e2dd3560c386c09c48d30d"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RStankov%2FMiniForm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RStankov%2FMiniForm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RStankov%2FMiniForm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RStankov%2FMiniForm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RStankov","download_url":"https://codeload.github.com/RStankov/MiniForm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243725071,"owners_count":20337660,"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","form","gem","ruby"],"created_at":"2024-10-11T13:30:25.653Z","updated_at":"2025-03-15T11:33:17.075Z","avatar_url":"https://github.com/RStankov.png","language":"Ruby","readme":"[![Gem Version](https://badge.fury.io/rb/mini_form.svg)](http://badge.fury.io/rb/mini_form)\n[![Code Climate](https://codeclimate.com/github/RStankov/MiniForm.svg)](https://codeclimate.com/github/RStankov/MiniForm)\n[![Code coverage](https://coveralls.io/repos/RStankov/MiniForm/badge.svg?branch=master)](https://coveralls.io/r/RStankov/MiniForm)\n\n# MiniForm\n\nHelpers for dealing with form objects and nested forms.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'mini_form'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install mini_form\n\n## Usage\n\n```ruby\nclass ProductForm\n  include MiniForm::Model\n\n  attributes :id, :name, :price, :description\n\n  validates :name, :price, :description, presence: true\n\n  # called after successful validations in update\n  def perform\n    @id = ExternalService.create(attributes)\n  end\nend\n```\n\n```ruby\nclass ProductsController \u003c ApplicationController\n  def create\n    @product = ProductForm.new\n\n    if @product.update(product_params)\n      redirect_to product_path(@product.id)\n    else\n      render :edit\n    end\n  end\n\n  private\n\n  def product_params\n    params.require(:product).permit(:name, :price, :description)\n  end\nend\n```\n\n### Delegated attributes\n\nAttributes can be delegated to a sub object.\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  attr_reader :account, :user\n\n  attributes :name, :email, delegate: :user\n  attributes :company_name, :plan, delegate: :account\n\n  validates :name, :email, :company_name, :plan, presence: true\n\n  def initialize\n    @account = Account.new\n    @user    = User.new account: @account\n  end\n\n  def perform\n    user.save!\n    account.save!\n  end\nend\n```\n\n```ruby\nform = SignUpForm.new\nform.name = 'name' # =\u003e form.user.name = 'name'\nform.name          # =\u003e form.user.name\nform.plan = 'free' # =\u003e form.account.plan = 'free'\nform.plan          # =\u003e form.account.plan\n```\n\n### Nested validator\n\n`mini_form/nested` validator runs validations on the given model and copies errors to the form object.\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  attr_reader :account, :user\n\n  attributes :name, :email, delegate: :user\n  attributes :company_name, :plan, delegate: :account\n\n  validates :account, :user, 'mini_form/nested' =\u003e true\n\n  def initialize\n    @account = Account.new\n    @user    = User.new account: @account\n  end\n\n  def perform\n    account.save!\n    user.save!\n  end\nend\n```\n\n### Nested models\n\nCombines delegated attributes and nested validation into a single call.\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  model :user, attributes: %i(name email)\n  model :account, attributes: %i(company_name plan)\n\n  def initialize\n    @account = Account.new\n    @user    = User.new account: @account\n  end\n\n  def perform\n    account.save!\n    user.save!\n  end\nend\n```\n\n### Auto saving nested models\n\nMost of the time `perform` is just calling `save!`. We can avoid this by using `model`'s `save` option.\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  model :user, attributes: %i(name email), save: true\n  model :account, attributes: %i(company_name plan), save: true\n\n  def initialize\n    @account = Account.new\n    @user    = User.new account: @account\n  end\nend\n```\n\n### Before/after callbacks\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  # ... code\n\n  before_update :run_before_update\n  after_update :run_after_update\n\n  private\n\n  def run_before_update\n    # ...\n  end\n\n  def run_after_update\n    # ...\n  end\n\n  # alternatively you can overwrite \"before_update\"\n  def before_update\n  end\n\n  # alternatively you can overwrite \"after_update\"\n  def after_update\n  end\nend\n```\n\n### Using in forms\n\nUsing `main_model` will delegate `id`, `to_param`, `persisted?` and `new_record?` to the model. Allowing you to use it in forms.\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  main_model :user\n\n  def initialize\n    @user = User.new(account: @account)\n  end\nend\n```\n\n```eruby\n\u003c% form_for SignUpForm.new %\u003e\n```\n\n### Delegating model attributes\n\n```ruby\nclass SignUpForm\n  include MiniForm::Model\n\n  model :user, attributes: %i(name email), read: %i(id)\n\n  def initialize\n    @user = User.new(account: @account)\n  end\nend\n```\n\n```\nform = SignUpForm.new\nform.update! form_params\nform.id        # =\u003e delegates to `user.id`\nform.id = 42   # =\u003e raises `NoMethodError`\n```\n\n### Methods\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eMethod\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e.model\u003c/td\u003e\n    \u003ctd\u003eDefines a sub object for the form\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e.attributes\u003c/td\u003e\n    \u003ctd\u003eDefines an attribute, it can delegate to sub object\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e.attribute_names\u003c/td\u003e\n    \u003ctd\u003eReturns list of attribute names\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#initialize\u003c/td\u003e\n    \u003ctd\u003eMeant to be overwritten. By defaults calls `attributes=`\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#attributes=\u003c/td\u003e\n    \u003ctd\u003eSets values of all attributes\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#attributes\u003c/td\u003e\n    \u003ctd\u003eReturns all attributes of the form\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#update\u003c/td\u003e\n    \u003ctd\u003eSets attributes, calls validations, saves models and `perform`\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#update!\u003c/td\u003e\n    \u003ctd\u003eCalls `update`. If validation fails, it raises an error\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#perform\u003c/td\u003e\n    \u003ctd\u003eMeant to be overwritten. Doesn't do anything by default\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#before_update\u003c/td\u003e\n    \u003ctd\u003eMeant to be overwritten.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#after_update\u003c/td\u003e\n    \u003ctd\u003eMeant to be overwritten.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#before_assignment\u003c/td\u003e\n    \u003ctd\u003eMeant to be overwritten.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#after_assignment\u003c/td\u003e\n    \u003ctd\u003eMeant to be overwritten.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e#transaction\u003c/td\u003e\n    \u003ctd\u003eIf ActiveRecord is available, wraps `perform` in transaction.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Run the tests (`rake`)\n6. Create new Pull Request\n\n## License\n\n**[MIT License](https://github.com/RStankov/MiniForm/blob/master/LICENSE.txt)**\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frstankov%2Fminiform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frstankov%2Fminiform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frstankov%2Fminiform/lists"}