0

I have four loops in my haml document for testing purposes with the only difference being the order of the elements.

Am I somehow able to put the logic in my controller and list the whole 'insidyness' of the loop only once in my haml document?
Currently I have everything duplicated 4 times and ya know, that feels bad. :)

For instance:

- @loop.where(featured: true).order("RANDOM()").limit(4).each do |item|
    %li
        %h1 This is an example
- @loop.order(:cached_votes_up => :desc).limit(4).each do |item|
    %li
        %h1 This is an example
- @loop.order(:impressions_count => :desc).limit(4).each do |item|
    %li
        %h1 This is an example
- @loop.order("created_at DESC").limit(4).each do |item|
    %li
        %h1 This is an example

Controller:

def index
    @loop = Item.all
end

I would like to reduce my Haml Code to something like this and move the rest in the Controller:

- @loop.each do |item|
    %li
        %h1 This is an example

Thanks in advance for each answer!

9
  • What is @loop? what are you exactly trying to do? without understanding the problem we can not help you. Commented Sep 19, 2016 at 4:51
  • Sorry, I added that to the answer :) Commented Sep 19, 2016 at 5:04
  • Show what you expect. Commented Sep 19, 2016 at 5:06
  • You can write the same loop logic in the controller and save it another instance variable and just call that from the haml file. Like inside index def, you can add @loop.order(:cached_votes_up => :desc).limit(4).each do |item| @cached_votes_up += item end Commented Sep 19, 2016 at 5:13
  • @Bartek Gładys Updated question. Commented Sep 19, 2016 at 5:15

3 Answers 3

2

You can't render the view multiple times but you could do something like this.

def index
  @loops = [
    Item.where(featured: true).order("RANDOM()"),
    Item.order(:cached_votes_up => :desc),
    Item.order(:impressions_count => :desc),
    Item.order("created_at DESC")
  ]
end

And then in the template

- @loops.each do |loop|
 - loop.limit(4).each do |item|
   %li
     %h1 This is an example
Sign up to request clarification or add additional context in comments.

4 Comments

Just one question regarding this: Will this render everything four times with different orders (as intended), or will this just combine everything to one loop?
It's two loops. The first loop calls the second loop 4 times (each time with the items in a different order). The second loop renders the html for each item in that loop.
And where do you init the loop-loop?
Right there in the template. - @loops.each ... is looping over the loops. and ` - loop.limit(4).each ...` is looping through each loop.
2

in Item model class:

scope :featured_with_random_order_desc, ->(limit_value) { where(featured: true).order("RANDOM()").limit(limit_value) }

scope :by_cached_votes_order_desc, ->(limit_value) { order(:cached_votes_up => :desc).limit(limit_value) }

scope :by_impression_count_order_desc, ->(limit_value) { order(:impressions_count => :desc).limit(limit_value) }

scope :by_created_at_desc, ->(limit_value) { order("created_at DESC").limit(limit_value) }

In your views:

- @loop.featured_with_random_order_desc(4).each do |item|
    %li
        %h1 This is an example
- @loop.by_cached_votes_order_desc(4).each do |item|
    %li
        %h1 This is an example
- @loop.by_impression_count_order_desclimit(4).each do |item|
    %li
        %h1 This is an example
- @loop.by_created_at_desc.limit(4).each do |item|
    %li
        %h1 This is an example

You can go one more step further and create variable for each loop in your controller:

def index
  @loop_featured = Item.featured_with_random_order_desc(4)
  @loop_cached_votes = Item.by_cached_votes_order_desc(4)
  @loop_impression_counts = Item.by_impression_count_order_desclimit(4)
  @loop_by_created = Item.by_created_at_desc(4)
end

and use them in view:

- @loop_featured.each do |item|
  %li
    %h1 This is an example
- @loop_cached_votes.each do |item|
  %li
    %h1 This is an example
- @loop_impression_counts.each do |item|
  %li
    %h1 This is an example
- @loop_by_created.each do |item|
  %li
    %h1 This is an example

Comments

0

You can use union_scope from ActiveRecord

    #item.rb

    include ActiveRecord::UnionScope
    scope :by_random, -> { where(featured: true).order("RANDOM()").limit(4) }
    scope :by_cached_votes, ->{ order(:cached_votes_up => :desc).limit(4) }
    scope :by_impression_count, ->{ order(:impressions_count => :desc).limit(4) }
    scope :by_created_at, ->{ order("created_at DESC").limit(4) }

    scope: all_conditions, -> { union_scope(by_random, by_cached_votes,by_impression_count,by_created_at}

your controller

@item = Item.all_conditions

your view:

- @loop.all_conditions.each do |item|

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.