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" %>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With