Black Dynamite
Black Dynamite

Reputation: 4147

Ruby on Rails - edit/new and show in same partial

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

Answers (3)

Brian
Brian

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

Monty
Monty

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

Valery Kvon
Valery Kvon

Reputation: 4496

 <%= fields_for @object do |f| %>
   <%= render 'your/fields_parial', :f => f %>
 <% end %>

Upvotes: 1

Related Questions