Search code examples
ruby-on-railsrubynested-resources

Nested Resources in Rails views


I know there are many articles on Rails nested resources and I went through a lot of them but nothing answers my question.

I have 3 models: user, group and micropost. User subscribes to groups, each having a number of microposts. All the association are in place and working fine.

What I want to achieve is to have the homepage where users have tabs of their groups, each listing the microposts within that group.

This is what I am doing at the moment:

#Home Controller
def home
 if logged_in?
  @groups=current_user.group
 end
end

I have created a function in the user model that returns microposts belonging to a specific group

def group_feed(group_id)
     microposts_ids = "SELECT micropost_id from groupings WHERE group_id IN (#{group_id})"
     Micropost.where("id IN (#{microposts_ids})")
end

In my view

    <div class="panel-body">
    <div class="tab-content">
      <% @groups.each do |group| %>

      <div class="tab-pane fade <%= 'in active' if current_user.group.first == group %>" id="<%=(group.name.gsub(/[0-9]+/, "")+group.id.to_s).parameterize%>">

        <div class="panel panel-default">

         <%= render current_user.group_feed(group.id) %>

       </div>

     </div>
     <% end %>
   </div>
 </div>

This is working fine at the moment, but I suspect it is the right way to do it. I would like to be able to pass resources from the controller to the view rather than calling the model action from the view.

Is there any way to define @microposts in the controller and having it nested under each group in @groups?


Solution

  • I think the way your view works is quite normal, but I suspect that the way you are using relationships in the database is non railsy at the least.

    I assume you are using ActiveRecord.

    Inside your models you should have something like this.

    # app/models/user.rb
    class User
      has_many :groupings
      has_many :groups, through: :groupings
    end
    
    # app/models/grouping.rb
    class Grouping
      belongs_to :group
      belongs_to :user
    end
    
    # app/models/group.rb
    class Group
      has_many :microposts
      # this would be optional
      has_many :groupings
      has_many :users, through: :groupings
    end
    
    # app/models/micropost.rb
    class Micropost
      belongs_to :group
    end
    

    Thus in your controller you could set @groups = current_user.groups and in your view you could call group.microposts.each.

    If you wanted to set both in the controller you could do something like this:

    @groups = current_user.groups
    @microposts = @groups.map(&:microposts)
    

    And then in your view you could call:

    @groups.each_with_index do |group, index|
      # do something with group
      @microposts[index].each do |micropost|
        # do something with micropost
      end
    end
    

    But this is kind of tedius.