module ApplicationHelper class TabularFormBuilder < ActionView::Helpers::FormBuilder (field_helpers - [:label]).each do |selector| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{selector}(method, options = {}) @template.content_tag :tr do @template.content_tag(:td, label_for(method, options)) + @template.content_tag(:td, super, @object&.errors[method].present? ? {class: "error", data: {content: @object&.errors.delete(method).join(" and ")}} : {}) end end RUBY_EVAL end def label_for(method, options = {}) return "" if (options[:label] == false) text = options.delete(:label) text ||= @object.class.human_attribute_name(method).capitalize classes = @template.class_names(required: options[:required], error: @object&.errors[method].present?) label(method, text, class: classes) + (@template.tag(:br) + @template.content_tag(:em, options.delete(:hint)) if options[:hint]) end def submit(value, options = {}) @template.content_tag :tr do @template.content_tag :td, super, colspan: 2 end end def table_form_for(&block) @template.content_tag(:table) { yield(self) } + # NOTE: display leftover error messages (there shouldn't be any) @template.content_tag(:div, @object&.errors.full_messages.join(@template.tag :br)) end end def tabular_form_for(record, options = {}, &block) options.merge! builder: TabularFormBuilder form_for(record, **options, &-> (f) { f.table_form_for(&block) }) end def image_link_to(name, image = nil, options = nil, html_options = {}) return "" if html_options.delete(:unless_current) && (url_for(options) == request.path) name = svg_tag("pictograms/#{image}.svg#icon") + name if image link_to name, options, html_options.merge!(class: "image-button") { |k, v1, v2| "#{v1} #{v2}" } end def svg_tag(source, options = {}) image_name, id = source.split('#') content_tag :svg, options do tag.use href: "#{image_path(image_name)}##{id}" end end end