DynamicFormReflex
Create and manage complex forms with page morphs
How?
- A model (
Address
) has associations to two interdependent other models (Country
=>State
) - Via a
DynamicFormReflex#refresh
action, manage thestate_id
select box, which depends on thecountry
Caveat
To use this with unpersisted records, you will need to adapt the def resource
method slightly:
def resource
@resource ||= if element.dataset.sgid.present?
element.signed[:sgid]
else
element.dataset.resource_name.classify.new
end
end
Variations
- You can also use this with
has_many
associations:
class Address < ApplicationRecord
belongs_to :tenant
has_many :inhabitants
accepts_nested_attributes_for :inhabitants
class Controller
def edit
@address = Address.find(params[:id])
@address.inhabitants.build
end
end
<%= form_with model: @address do |form| %>
<%= form.label :tenant_id %>
<%= form.collection_select :tenant_id, Tenant.all, :id, :name, {include_blank: true},
data: {reflex: "change->DynamicForm#refresh", sgid: @address.to_sgid.to_s,
resource_name: "address", association: "tenant"} %>
<%= form.fields_for :inhabitants do |inhabitant_fields| %>
<%= inhabitant_fields.label :inhabitant_id %>
<%= inhabitant_fields.collection_select :inhabitant_id, @address.tenant&.members || [], :id, :name %>
<% end %>
<% end %>
app/reflexes/dynamic_form_reflex.rb
class DynamicFormReflex < ApplicationReflex
def refresh
resource.send("#{element.dataset.association}=", element.dataset.association.classify.safe_constantize.find(element.value))
instance_variable_set "@#{element.dataset.resource_name}", resource
end
def resource
@resource ||= element.signed[:sgid]
end
end
app/controllers/addresses_controller.rb
class AddressesController < ApplicationController
def edit
@address = Address.find(params[:id])
end
end
app/models/address.rb
class Address < ApplicationRecord
belongs_to :country
belongs_to :state
end
app/models/country.rb
class Country < ApplicationRecord
has_many :states
end
app/models/state.rb
class State < ApplicationRecord
belongs_to :country
end
app/views/addresses/edit.html.erb
<%= form_with model: @address do |form| %>
<%= form.label :country_id %>
<%= form.collection_select :country_id, Countries.all, :id, :name,
{include_blank: true}, data: {reflex: "change->DynamicForm#refresh",
sgid: @address.to_sgid.to_s, resource_name: "address", association: "country"} %>
<%= form.label :state_id %>
<%= form.collection_select :state_id, @address.country&.states || [], :id, :name %>
<%= form.submit %>
<% end %>