0

I have multiple models that their indexes views are nearly share the exact same code, and layout.

.../chocolates/index.html.erb

<h1 class="col-sm-12 head">Index Bases</h1>
<hr>
<% @chocolates.each do |chocolate| %>

  <%= link_to chocolate do %>
    <%= set_img(chocolate) %>
  <% end %> 

  <ul>
    <li><%= chocolate.name %></li>
    <li><%= chocolate.position %></li>
  </ul>
  <hr>

  <div>
    <%= link_to chocolate do %>
      <span class="glyphicon glyphicon-eye-open"></span>
    <% end %> 
    <%= link_to edit_chocolate_path(chocolate) do %> 
      <span class="glyphicon glyphicon-edit"></span>
    <% end %>
    <%= link_to basis, method: :delete, data: { confirm: 'Are you sure?' } do %> 
      <span class="glyphicon glyphicon-remove"></span>
    <% end %>
  </div>

<% end %>
<hr>
<%= link_to '+ Add New Chocolate', new_chocolate_path %>

.../sweets/index.html.erb

<h1 class="col-sm-12 head">Index Bases</h1>
<hr>
<% @sweets.each do |sweet| %>

  <%= link_to sweet do %>
    <%= set_img(sweet) %>
  <% end %> 

  <ul>
    <li><%= sweet.name %></li>
    <li><%= sweet.position %></li>
  </ul>
  <hr>

  <div>
    <%= link_to sweet do %>
      <span class="glyphicon glyphicon-eye-open"></span>
    <% end %> 
    <%= link_to edit_sweet_path(sweet) do %> 
      <span class="glyphicon glyphicon-edit"></span>
    <% end %>
    <%= link_to sweet, method: :delete, data: { confirm: 'Are you sure?' } do %> 
      <span class="glyphicon glyphicon-remove"></span>
    <% end %>
  </div>

<% end %>
<hr>
<%= link_to '+ Add New Sweet', new_sweet_path %>

And there are more models that share the same layout, And I thought that I keep repeating my self so I created a shared partial with variables to render in each view that uses that layout using.

.../sweets/index.html.erb

<% render 'shared/indexGrid', dist: @sweets%>

.../views/shared/_indexGrid.html.erb

<% title = dist.class.name.underscore.tr('_', ' ').pluralize.split.map(&:capitalize).join(' ') %>
<% sing = dist.class.name.underscore %>

<h1>Index <% title %></h1>
<hr>

<% dist.each do |sing| %>

  <%= link_to sing do %>
    <%= set_img(sing) %>
  <% end %> 

  <ul>
    <li><%= sing.name %></li>
    <li><%= sing.position %></li>
  </ul>
  <hr>

  <div>
    <%= link_to sing do %>
      <span class="glyphicon glyphicon-eye-open"></span>
    <% end %> 

    <%= link_to send("edit_#{sing.class.name.underscore}_path", sing) do %> 
      <span class="glyphicon glyphicon-edit"></span>
    <% end %>

    <%= link_to sing, class: 'square red', method: :delete, data: { confirm: 'Are you sure?' } do %> 
      <span class="glyphicon glyphicon-remove"></span>
    <% end %>
  </div>
<% end %>
<hr>
<%= link_to "+ Add New #{title}", send("new_#{sing.class.name.underscore}_path"), { class: 'btn btn-success btn-block'} %>

But It didn't seems to work because -I think- dist.class.name deasnt return the value I was expecting but returns "active_record/relation". I've tried a same approach before with edit views and It worked with dist: @sweet.

I've Thought of using layouts but It left me with big chunks of code that are very similar to the other index view.

I've shared my attempts with you, And the questions are...

  • What's wrong with my code and how to fix it?
  • Is this approach considered to be a good practice for DRY code? and If not What is the best way to share same view code with multiple models when those models are nearly shares the exact same code and layout?

2 Answers 2

1

you can try model_name

<% title = dist.model_name.to_s.underscore.tr('_', ' ').pluralize.split.map(&:capitalize).join(' ') %>

or better yet

  <% title = dist.model_name.human.pluralize.titleize  %>

should also give you what you want.

and to clean up the routes, you can look at PolymorphicRoutes

http://api.rubyonrails.org/classes/ActionDispatch/Routing/PolymorphicRoutes.html

so instead of

link_to send("edit_#{sing.class.name.underscore}_path", sing)

you can use something like

link_to 'Edit, edit_polymorphic_path(sing)

That should clean up your shared index page nicely.

You could also look at creating a title_for (for example ) helper that returns the title. to clean it up, but not 100% required.

-- part 2 --

Is it a good idea? Maybe? how is that for a non answer. There are a lot of factors. How likely is that all of these models will always all be exactly the same? How hard / much work will it be to make one different later on? If I had a bunch of models that where all basically the same, were always going to have the same exact index pages, I would probably look at doing something similar to this. Same kind of idea is used with engines / gems /plugins that generate views and the like automatically. So I guess if they are always going to be the same, and you would always like to keep it all looking the same, that something like this is perfectly fine.

As for collections in partials when you look at something like @sweets, it isn't a single instance of your model. It is probably an ActiveRelation. so calling model_name from active_model isn't going to be much help there. If you look at rails guides on partials, you will see render @collection. That basically just iterates of each object in the collection, looks at the model_name for you, and passes it to its corresponding partial to render.

So if you have a collection of @sweets, which had a bunch of Sweet objects in it, rails will iterate the collection. and then render _sweet.html.erb (following the normal rules for locating which partial), for you. With this you can adjust your <% dist.each do |sing| %> block to be <%=render dist%> and then just make sure each model has a partial and it can render them all differently

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks man for the great answer, It's working just fine now, But the second part of my question is still not answered, So do you think this is the best approach to do such a thing? Do you think It's right at all to share views among models -performance wise or so- . I was looking at the Partial documentation and I found something called collection I doubted that has something to do with such cases, Also when I ran @sweets.model_name It returned a hash with a lot of values like named routs and other instances variables I also doubted it could help.
last thing, Would you recommend using layout rather than this?
I am not sure I would put it in a layout, since then you are going to have different layouts for different actions, in each of your controllers, and that gets confusing , quick.. The rendering of the shared partial is explicit, and actually makes changing away from it later on easier if the need arrives(just change index.html.erb as opposed to adjusting the controller to change the layout for the action)
0

An easy solution is to use partials including class_name as a parameter

 <% render 'shared/indexGrid', dist: @sweets, class_name = "Sweets"%>

Or add something allows you to recognize which is the source....

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.