Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying validation errors on delegate attributes

I have the following (where Venue is a CTI descendant of Actor):

class Actor < ActiveRecord::Base
  has_one :profile, validate: true, autosave: true
end

class Venue < ActiveRecord::Base
...
  %w{description address website phone}.each do |attr|
    delegate attr.to_sym, "#{attr}=".to_sym, to: :profile!
  end

  def profile!
    actor.profile || actor.build_profile
  end
...
end

I'm including the fields for those delegate attributes directly in the Venue form. When one of these attributes fails its validation, all I see is the notification on top, but not the wrapper around the field. I guess this must be because the key in the errors hash of the Venue instance does not quite match the attribute name, being set to :"actor.profile.website" instead of just :website.

Is there any way I can make these errors display properly?

EDIT

Here's the form:

<%= simple_form_for @venue do |f| %>
  <%= f.error_notification %>

  <%= f.input :name %>
  <%= f.input :address, required: true %>
  <%= f.input :phone %>
  <%= f.input :website %>
  <%= f.input :members, collection: [], class: "form_tag" %>
  <%= f.input :tag_list, as: :string, class: "form_tag", hint: t("misc.hint.tag"),
              input_html: { "data-pre" => @venue.tag_list.map {|t| { id: t, name: t }}.to_json } %>
  <%= f.input :description, as: :text, input_html: {rows: 6, cols: 53, class: "form_tag"} %>

  <div class="actions center">
<%= f.submit class: "btn btn-success" %>

like image 370
HargrimmTheBleak Avatar asked Jun 27 '26 21:06

HargrimmTheBleak


1 Answers

That's right. And the way to correct is to use stuff like that:

class Venue < ActiveRecord::Base
...
  after_validation do
    if errors.any?
      errors.messages.keys.each do |key|
        errors.messages[key.to_s.gsub(/actor.profile./, "").to_sym] = errors.messages.delete(key)
      end
    end
  end
...
end

Updated:

HOWTO Just Wrap Content with div class="field_with_error"

Notice: Rails wraps fields only if the base object has errors and errors has an appropriate key equal to attribute name (actually method name). For nested associated attributes it uses prefixed key (actor.profile.website) according to an associated sequence.

By the way, the common method:

<%= field_error_proc.call(content) %>

# where content is any string/symbol stuff.

Trigger for errors handling:

<%= form_for... do |f| %>
  <% website_field = capture do %>
    <%= f.text_field :website %>
  <% end %>

  <% if f.object.errors[:"actor.profile.website"] %>
    <%= website_field %>
  <% else %>
    <%= field_error_proc.call(website_field) %>
  <% end %>
<% end %>

A little tedious right? It is better to use Rails' native mechanism of wrapping.

See the next answer.

like image 117
Valery Kvon Avatar answered Jun 29 '26 13:06

Valery Kvon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!