Skip to content
Jake Goulding edited this page Mar 7, 2018 · 8 revisions

Provide a default value if the model value is nil

property :foo, default: 'default'

Set an initial value when form is created

This is a separate use case to "provide a default if empty" shown above. You want to do this if you want to set an initial value, but allow nil to be set as a value without it falling back to the default value when falsey.

# Remember to call `form.prepopulate!` to make this work.
property :foo, prepopulator: -> (*) { self.foo = "initial value" }

Automatically prepopulate a property on the form from the model.

prepopulate! is designed to called manually, but if you want to set a property value based on a property on the model, you can sneakily add it in the initializer.

def initialize *args
  super(*args)
  self.some_property = "#{model.some_property} #{model.some_other_property}"
end

Make a collection form behave like a collection in the UI.

class ItemForm < Reform::Form
 ...
end

class ListForm < Reform::Form

  # entries is the name of the method on an array that will return itself
  collection :entries, form: ItemForm

  def each
    entries.each { | entry | yield entry }
  end

  def map
    entries.map { | entry | yield entry }
  end

  def count
    entries.count
  end

  def empty?
    entries.empty?
  end

  def any?
    entries.any?
  end
end

# in the controller

@items = ListForm.new(Item.all)

# in the UI - no change! 

@items.each do | item |
  ...
end

Sort collection before presenting

class ListForm < Reform::Form

  collection :entries, form: ItemForm

  def initialize entries
    super sort_entries(entries)
  end

  def sort_entries entries
    entries{ | a, b| a.created_at <=> b.created_at }
  end
end

Using validations on the form and the model together.

For example, when you have a database validation like validates_uniqueness_of, or you are using another gem that only plays with ActiveRecord models (eg. Devise).

This actually belongs in the Trailblazer::Operation docs... you could probably hack the same thing by overriding form.save.

class User::Create < Trailblazer::Operation
  def process(params)
    validate(params[:user]) do | form |
      unless form.save
        model.errors.each do | key, message |
          contract.errors.add(key, message)
        end        
        invalid!
      end
    end
  end
end

Provide default values from external source (e.g. HTTP parameters)

If you want to provide default values from an external source then you can use deserialize to populate the values without running the validations.

e.g. inside a controller

def new
  form = MyForm.new(MyModel.new)
  form.deserialize(params)
  ...
end