Using the Rails form builder and Draper

452 views Asked by At

I'm giving Draper a try as an alternative to helpers. I get the cases where I am just formatting the information. But what about interacting with the Rails form builder. For example if I wanted to output a string or a select box depending on some context. Do I pass the form builder as an argument. So in my decorator:

def role_or_select form
  available_roles = h.policy_scope User::ROLES
  if available_roles.include? role
    form.input :role, collection: available_roles, include_blank: false
  else
    role
  end
end

Then in my view:

= simple_form_for user do |form|
  ...
  = user.role_or_select_on form
  ...

Is there a more elegant method?

1

There are 1 answers

0
Eric Anderson On

I think I found a somewhat elegant solution to this. I created the following module and mixed it into my decorators:

module FormDecoration

  def form options={}, &blk
    h.simple_form_for model, options do |builder|
      @form_builder = builder
      blk[builder]
    end
  ensure
    @form_builder = nil
  end

  def method_missing meth, *args, &blk
    if @form_builder && @form_builder.respond_to?(meth)
      @form_builder.public_send meth, *args, &blk
    else
      super
    end
  end

  def respond_to? meth
    (@form_builder && @form_builder.respond_to?(meth)) || super
  end
end

Now my view can be this:

= user.form do
  = user.input :name
  = user.input :email
  = user.role_or_select

The input method is proxied off to the form builder. The role_or_select is defined in my helper to look something like this:

  def role_or_select
    available_roles = h.policy_scope User::ROLES
    if available_roles.include? object.role
      input :role, collection: available_roles, include_blank: false
    else
      object.role
    end
  end

This even allows me to do things like add the form options in the decorator. For example adding the following to my UserDecorator will turn off the auto-complete:

def form options={}
  options[:html] ||= {}
  options[:html][:autocomplete] = 'off'
  super options
end