Michael
Michael

Reputation: 139

Rails (6.0). View each block element not recognized inside nested partial?

Rails beginner project In a view that I want to show all results from two different models (MediaLink & MediaCollection) I have successfully created a two dimensional array @ranked_media that holds

[0] is id from table
[2] is total_points
[5] is class name as a string.

Being that they are pulled from 2 different tables, the id can be repeated twice, but won't have the same class name if id are identical.

In my view (pages/media.html.erb) :

<div class="container">
    <% @ranked_media.each do |media| %>
        <% if media[5] == 'MediaCollection' %>
          <%= render 'media_collection_show' %>
        <% else %>
          <%= render 'media_link_show' %>
        <% end %>
        
    <% end %>
</div>

partial _media_collection_show.html.erb :

<h2 class="text-center mt-4 text-white">
     is a MEDIA COLLECTION of class :: <%= @media_collections.class %>
</h2>

partial _media_link_show.html.erb :

<h2 class="text-center mt-4 text-white">
  is a MEDIA LINK of class :: <%= @media_links.class %>
</h2>

At this point all is fine. The block is being generated 5 times and applies the output according to the each block. The partials also outputs the class name to make sure they all work.

My Problem

However, I can add this to the view (3rd line is the change) :

<div class="container">
    <% @ranked_media.each do |media| %>
      <%= media %>
        <% if media[5] == 'MediaCollection' %>
          <%= render 'media_collection_show' %>
        <% else %>
          <%= render 'media_link_show' %>
        <% end %>
    <% end %>
</div>

And it outputs media object. But if try that in any of the partials like this :

<h2 class="text-center mt-4 text-white">
  is a MEDIA LINK of class :: <%= @media_links.class %>
  <%= media %>
</h2>

I get NameError in Pages#media undefined local variable or method `media'

How can I access the media block element inside these two partials?

Upvotes: 0

Views: 52

Answers (1)

Cassandra S.
Cassandra S.

Reputation: 770

By sending in local variables to the partials: <%= render 'media_link_show', media: media %>. In the partial you'd access it like so:

<h2 class="text-center mt-4 text-white">
     is a MEDIA Object of class :: <%= media.class %>
</h2>

Note the lack of @; in general it's bad form to access instance variables in partials.

Your third line (<%= media %>) also does nothing for the functionality, and can safely be removed.

Edit: When a controller does @items = ... in an action, it sets @items as an instance variable; any view rendered from that action has access to that value, which is why your @ranked_media can be looped over.

Partials are meant to be re-used, and not necessarily by the same view/controller, so if a partial accesses an instance variable, like your _media_collection_show.html.erb does, then any view/controller that uses that partial will need to set the @media_collections variable.

To avoid this (a controller action should strive to only set one instance variable), you can instead inject local variables into a partial: <%= render "partial_name", items: @items %>. Here, we're setting the local variable items to be the value of @items. By doing this, any view that uses the partial can send in their own items into the partial, without the need for the controller to set a "magical variable" @items. You could, for example, do: <%= render "partial_name", items: [1, 2, 3] %>. You've decoupled the partial from the controller.

Upvotes: 1

Related Questions