How to loop through model scopes to generate a listing?

Hello all,

I am wondering how I can loop through the scopes defined in a model. As an example, if I want to create an erb template that lists the content of of a model separated by scope with the header of that content being the scope name, I would like to be able to do this without having to create a specific loop for each scope.

Instead of something like

Scope1

<% Model.scope1.each do |record| %> <%= record.attribute%> <% end %>

Scope2

<% Model.scope2.each do |record| %> <%= record.attribute%> <% end %>

``

I would like to do something like

%w(scope1 scope2).each do |scope|

<%= scope %>

<% Model.scope.each do |record| %> <%= record.attribute%> <% end%> <% end %>

``

Which hopefully would give me the same output with less code. Does anyone have any ideas on how I might be able to accomplish this?

Thanks

You can use send method for calling scopes as followed:

<%- %w(scope1 scope2).each do |scope|
<h1><%= scope %></h1>
  <%- Model.send(scope.to_sym).each do |record| %>
    <%= record.attribute%>
  <%- end%>
<%- end %>

Thanks,
Lauree
Ruby on Rails Developer
Allerin Technologies

You can use send method for calling scopes as followed:


<%- %w(scope1 scope2).each do |scope|
<h1><%= scope %></h1>
<%- Model.send(scope.to_sym).each do |record| %>
    <%= record.attribute%>
  <%- end%>
<%- end %>

However looping more than a scope may cause huge data to be rendered on a single page. I would suggest avoiding this.

Following is an way to you can avoid looping multiple scopes on a single page:

  1. Keeping a select list on the page may help you to display only selective data. For example say you are having model User as :
class User < ActiveRecord::Base

  scope :active, -> { where active: true }
scope :inactive, -> { where active: false }
end

Then your select list will be :

<%= select_tag(:scope_name, options_for_select([['All', 'all'], ['Active Users', 'active'], ['InActive Users', 'inactive'],...])) %>

Above select list will have options of All, Active Users, InActive Users with values as actual scope names that you are having in your model.
With JS/JQuery you can write coding to send a get request to the controller which you were using for displaying data. So when user will be selecting any option the page will get reloaded. It can be done using
following code:

$(function  (){
$('#scope_name').change(function    (){
window.location.replace('/users?scope_name='+ $(this  ).val());
})
}

With above coding you will be getting scope_name parameter in params in your controller.

Use this params to retrieve records in controller only as follows:
In my controller action:

def index
  @scope_name = if %w(all, active, inactive).includes?(params[:scope_name]) # taking care that proper scope name is passed here
    params[:scope_name  ]
else
    'all'
  end
    @records = User.send(@scope_name  .to_sym)
end
end

Now this @records can be used on the template(views/users/index.html.erb) for displaying the record attributes:

  <h1><%= @scope_name.titleize %></h1>
  <%- @records.each do |record| %>
    <%= record.first_name%>
  <%- end%>

This way you will be having selective data on a page and you will not have to fire any query from view.