From 33a1712edb80354592c886d8b370ad6e4e4f74bb Mon Sep 17 00:00:00 2001 From: Vladimir <78034441+VladimirShinkevich@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:03:01 +0300 Subject: [PATCH] update readme 1.0 (#23) --- README.md | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 238 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a68d3c0..ebbdc7c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,4 @@ # ActiveDryForm - -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/active_dry_form`. To experiment with that code, run `bin/console` for an interactive prompt. - -TODO: Delete this and the text above, and describe your gem - ## Installation Add this line to your application's Gemfile: @@ -19,10 +14,242 @@ And then execute: Or install it yourself as: $ gem install active_dry_form +--- + +## Base Usage + +### Under the hood ActiveDryForm [dry-validation](https://dry-rb.org/gems/dry-validation), [dry-monads](https://dry-rb.org/gems/dry-monads) + +```ruby +form = ProductForm.new(record: Product.find(1), params: { product: { title: 'n', price: 120 } }) + +form.validate # => checks field validity +form.validator # => #"n", + # :price=>120 + # errors={:name=>["minimum length 2"]} + # context={:form=>{:name=>"n", :price=>120}, + # :record=># +form.valid? # => false +form.persisted? # => true +form.errors # => {:name=>["minimum length 2"]} +form.base_errors = [] +form.errors_full_messages # => ['Cannot be less than 2 words'] +form.record # => # +form.data # => {:title=>"n", :price=>120} +form.data[:price] # => 120 +form.price # => '120' +form.name # => 'n' +form.update # Failure(:invalid_form) +``` + +Methods `form.update` and `form.create` return [Result monad](https://dry-rb.org/gems/dry-monads/1.3/result/) + +```ruby +# app/forms/product_form.rb + +class ProductForm < Form + fields :product do + params do + required(:title).filled(:string, min_size?: 2) + required(:price).filled(:integer) + optional(:description).maybe(:string) + optional(:upload_attachments).maybe(:array) + end + + # you can add any rules to validate your fields + + rule(:description) do + key.failure('Cannot be less than 2 words') if value.split.size < 2 + end + end + + action def update + # Here you can implement any business logic + + record.update!(data) + Success(record) + end + +end +``` -## Usage +In your controller -TODO: Write usage instructions here +```ruby +class ProductsController < ApplicationController + include Dry::Monads[:result] + + def new + @form = ProductForm.new + end + + def create # without monads + @form = ProductForm.new(params: params) + @form.validate + + if @form.valid? + Product.create!(@form) + + redirect_to products_path + else + render :new + end + end + + def edit + @form = ProductForm.new(record: Product.find(params[:id])) + end + + def update # with monads + product = Product.find(params[:id]) + + @form = ProductForm.new(record: product, params: params) + + case @form.update + in Success(product) + redirect_to product + else + render :edit + end + end +end +``` + +in your view (slim for example) + +```slim +/ app/views/products/new.slim + +- active_dry_form_for @form do |f| + = f.input :title + = f.input :price + = f.input_select :status, Product::STATUSES.values + = f.input_file :upload_attachments, multiple: true, label: false + = f.button 'Submit' +``` + +### Form attribute initialization + +In your controller + +```ruby +def new + @form = ProductForm.new(params: { product: { title: 'name', price: 120 } }) + @form.attributes = { title: 'new name', price: 100} + @form.description = 'product description' +end +``` + +or like this + +```ruby +def new + @form = ProductForm.new + @form.create_default(params[:title]) +end +``` + +then in your dry form + +```ruby +def create_default(title) + self.title = title +end +``` + +### Look at the inputs we have (slim for example) + +[input](https://github.com/corp-gp/active_dry_form/blob/master/lib/active_dry_form/builder.rb#L97) method automatically determines tag type: + +- by [dry type predicates](https://dry-rb.org/gems/dry-schema/main/basics/built-in-predicates/) - date, time, integer, number, string, boolean +- by field name - password, email, telephone, url + +```slim +- active_dry_form_for @form, html: { 'data-controller': 'product'} do |f| + = f.input :title, 'data-product-target': 'title', readonly: true, + = f.show_error(:title) + = f.input_select :category_id, Category.pluck(:name, :id), + { include_blank: true }, + { label: false, multiple: true, style: 'max-width:unset;'} + = f.input_check_box :is_discount + = f.input_checkbox_inline :is_sale + = f.input_text :shipper_name + = f.input_text_area :description + = f.input_hidden :admin_id + = f.input_file :upload_attachments, multiple: true, label: false + = f.input_date :date + = f.input_datetime :date_time + = f.input_integer :category_id + = f.input_number :number + = f.input_password :password + = f.input_email :email + = f.input_url :url + = f.input_telephone :telephone + + = f.button 'Submit' +``` + +### You can create your own input + +```ruby +# lib/acitve_dry_form/builder.rb + +module ActiveDryForm + class Builder + + def input_date_native(field, options = {}) + wrap_input(__method__, field, options) { |opts| date_field(field, opts) } + end + + end +end +``` + +### The form can be nested + +```ruby +class NestedDryForm < Form + + class BookmarkForm < Form + + fields(:bookmark) do + params do + required(:url).filled(:string) + optional(:id).maybe(:integer) + optional(:name).maybe(:string) + end + end + + end + + fields :product do + params do + required(:title).filled(:string, min_size?: 2) + required(:price).filled(:integer) + optional(:description).maybe(:string) + optional(:upload_attachments).maybe(:array) + optional(:bookmarks).array(Dry.Types::Instance(BookmarkForm)) + end + end + + action def update + bookmarks_data = data.delete(:bookmarks) + + record.attributes = data + record.bookmarks_attributes = bookmarks_data if bookmarks_data + record.save! + + Success(record) + end + +end +``` + +As you noticed in the above example, we use the construction `Dry.Types::Instance(BookmarkForm)`, +what it is `dry types` you can find out [here](https://dry-rb.org/gems/dry-types) + +--- ## Development @@ -30,10 +257,14 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run To 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). +--- + ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/active_dry_form. +--- + ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).