Search code examples
ruby-on-railsrubyloopsif-statementnested-loops

Nested loop with 'if' statements


I am trying to loop through an array of options, and check each option to see if it matches a different option within a different array. If the two options match, do one thing, if they don't match, do another thing.

I have 3^2 available options, and it runs through nine times. It goes (true, false, false), (false, true, false), (false, false, true), which isn't ideal. Instead, I'd like to see something along the lines of: (true), (false), (true).

It sits in my frontend in an erb file. I realize that there shouldn't be logic there, and am happy for refactoring suggestions but did plan on moving it out after I figured out how to make the loop work.

Frontend Code:

<% @available_sites.each do |available_site| %>
  <% @sites.each do |site| %>
    <% if site.review_site == available_site.name %>
      <div class="site-row columns">
        <div class="column col-4 col-md-10 col-mx-auto">
          <div class="site-tile">
            <a href="<%= site.direct_review_url %>" style="background-image: url(<%= image_path("review_site_logos/#{site.review_site}.png")%>); background-size: cover;"></a>
          </div>
        </div>
        <div class="column col-4 col-md-10 col-mx-auto">
          <span>Average Rating: <%= site.average_rating %></span>
          <span>Review Site: <a href="<%= site.direct_review_url %>"><%= site.review_site %></a></span>

        </div>
        <div class="column col-4 col-md-10 col-mx-auto is-flex-centered request-row-buttons">
          <%= link_to 'Show', [site.location, site] %>
          <%= link_to 'Edit', [:edit, site.location, site] %>
          <%= link_to 'Destroy', [site.location, site], method: :delete, data: { confirm: 'Are you sure?' } %>
        </div>
      </div>
    <% elsif site.review_site != available_site.name %>
      <div class="site-row columns">
        <div class="column col-4 col-md-10 col-mx-auto">
          <div class="site-tile">
            <a href="<%= available_site.link_to_info %>" style="background-image: url(<%= image_path("review_site_logos/#{available_site.name}.png")%>); background-size: cover;"></a>
          </div>
        </div>
        <div class="column col-4 col-md-10 col-mx-auto">
          <span>Sign Up for <%= available_site.name %> Business Page: <%= available_site.link_to_signup %></span>
          <span>Review Site: <a href="<%= site.direct_review_url %>"><%= site.review_site %></a></span>

        </div>
        <div class="column col-4 col-md-10 col-mx-auto is-flex-centered">
          <%= link_to "Add #{available_site.name} to Review App", new_location_site_path(review_site: "#{available_site.name}"), class: 'btn btn-primary' %>
        </div>
      </div>
    <% end %>
  <% end %>
<% end %>

Relevant Controller Code sites_controller.rb - policy_scope is for authorization:

def index
    @sites = policy_scope(@location.sites)
    @available_sites = AvailableSite.all
  end

Relevent Schema Code

create_table "sites", force: :cascade do |t|
    t.bigint "location_id"
    t.string "review_site"
    t.string "direct_review_url"
    t.string "place_id"
    t.decimal "average_rating"
    t.jsonb "extra_data", default: {}, null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "rating_count"
    t.index ["extra_data"], name: "index_sites_on_extra_data", using: :gin
    t.index ["location_id"], name: "index_sites_on_location_id"
  end
create_table "available_sites", force: :cascade do |t|
    t.string "name"
    t.string "link_to_info"
    t.string "link_to_signup"
    t.string "base_review_url"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["name"], name: "index_available_sites_on_name"
  end

I'm looking for help/a new direction on handling nested loops.


Solution

  • Just to make sure we're on the same page, I'm going to restate your problem:

    You have a list of AvailableSites and you want to display different information depending on if you have a visible Site for it.

    If that's accurate, you'll want to use find. Something like:

    <% @available_sites.each do |available_site| %>
      <% site = @sites.find { |s| s.review_site == available_site.name } %>
    
      <% if site.present? %>
        <%# view fragment when you have a site %>
      <% else %>
        <%# view fragment when you don't have a site %>
      <% end %>
    <% end %>
    

    This will only output one set of elements per AvailableSite.