Reputation: 4147
I have a relatively simple address partial that I use for 'new' and 'edit' forms for when an address is needed on an object. It works great. The problem is now that I want the same fields to show up on my 'show' views. The only problem is that my address partial requires a form which isn't present in a 'show' view. I would duplicate it, but that doesn't seem very DRY to have one partial for new/edit and another for show.
I was wondering if anyone has solved this problem. I have thought about using .new? and .persisted? but that doesn't really help because an object for editing will pass both of those in the same way a show object would.
Any help is greatly appreciated.
EDIT: Here is my address partial for new and edit. I would like to use the same partial as in the new,edit and show view, as recreating an entirely new partial doesn't seem very DRY. The issue I see is that this partial requires a form :f, which of course isn't available in a 'show' view.
<p>
<%= f.label :address_line_1, 'Address 1' %><br />
<%= f.text_field :address_line_1 %>
</p>
<p>
<%= f.label :address_line_2, 'Address 2' %><br />
<%= f.text_field :address_line_2 %>
</p>
<p>
<%= f.label :city %><br />
<%= f.text_field :city %>
</p>
<p class="address_state">
<%= f.label :state , "State" %><br />
<%= f.select :state, us_states, :include_blank => true %>
</p>
<p>
<%= f.label :zip_code, 'Zip Code' %><br />
<%= f.text_field :zip_code %>
</p>
Upvotes: 3
Views: 5140
Reputation: 43
Include a readonly
attribute in your fields, something like:
<%= f.text_field :name, readonly: @readonly %>
then place @readonly = true
in your show
method.
Upvotes: 2
Reputation: 188
I have the same concern, wanting to DRY out not just new/edit but show as well. With a lot of attributes on a model, it becomes a pain to maintain them in parallel across multiple views.
Poked around, could not find anything, except this (unresolved) post. And @Valery, isn't fields_for really meant for editing other models inside your form_for?
@FlexFiend, I ended up solving your problem this way (and admittedly, it's clunky, but it gets the job done): DO use a form also for the show view, and create a partial (shared by all actions) that calls helpers that test the controller action, and if "editable", then invoke the right control type. Otherwise else just render the attribute if it's a show action.
For example, the starting template (show, new, edit) simply invokes a form partial:
<%= render :partial => 'form' %>
...where _form is generic:
<%= form_for(@myObject) do |f| %>
<div>
<%= render :partial => "fields_for_all_actions", :locals => { :f => f } %>
</div
<% end %>
...and inside the partial, to either show or edit a 'name' attribute use a helper 'render_field':
<div><%= f.label :name %><span><%= render_field("@facility",f,"name", 30)%></span></div>
Inside the helper, render_field looks like this:
def render_field(object_name, f, attribute, txt_size=20)
if %w[new edit create update].include? controller.action_name
f.text_field(attribute.to_sym, :size => txt_size)
else
eval(object_name + "." + attribute)
end
end
I have created other helpers for other controls (text areas, radios, checkboxes, etc). These helpers are not model-specific, they live in application_helper.rb and can be used by multiple models.
It works, but I would be curious to know of other solutions to this problem, as the maintenance challenge of larger models is not insignificant. Granted, that argues perhaps for refactoring the model into component models, but that's another post.
Upvotes: 2
Reputation: 4496
<%= fields_for @object do |f| %>
<%= render 'your/fields_parial', :f => f %>
<% end %>
Upvotes: 1