Search code examples
ruby-on-railsfeedpolymorphic-associations

Rails polymorphic activity feed relations (multiple level)


I'm working on a polymorphic activity feed, and try to put feed items from different model mixing in one page.

I have these following models

  • User
  • Dashboard
  • Work
  • Project
  • ProjectRecord

Feed items include

  • Work
  • Project
  • ProjectRecord

models relation

class User < ActiveRecord::Base
   has_one :dashboard
   has_many :activities
   has_many :works
   has_many :projects
   has_many :project_records
end

class Work < ActiveRecord::Base
   belongs_to :user
end

class Project < ActiveRecord::Base
   belongs_to :user
   has_many :project_records
end

class Dashboard < ActiveRecord::Base
   belongs_to :user
   has_many :activities
end

class Activity < ActiveRecord::Base
   belongs_to :user
   belongs_to :subject, polymorphic: true
end

I define feed in User model, a user can follow others feed.

def feed
    following_ids = "SELECT followed_id FROM user_followings
                     WHERE  follower_id = :user_id"
    Activity.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
end

To build polymorphic activity feed, I have "after_create" in Work, Project, ProjectRecord model.

after_create :create_activity

    private

      def create_activity
        Activity.create(
          subject: self,
          user: user
        )
      end
end

Then, I try to list feeds(work, project, project record) in dashboard(controller)/show(action) page.

Here is my dashboards controller

class DashboardsController < ApplicationController

  before_action :authenticate_user!
  before_action :only_current_user    

  def show
    @feed_items = current_user.feed.order(created_at: :desc)
  end

  private
  def only_current_user
      @user = User.find( params[:user_id] )
      redirect_to(root_url) unless @user == current_user
  end    
end

In dashboard/show view

<% if @feed_items.any? %>

    <div class="feed-listing">
       <% @feed_items.each do |feed| %>
          <% if feed.subject_type == 'Work' %>
            <%= link_to polymorphic_path(feed.subject) do %>
              <%= render "activities/work_feed", subject: feed.subject, :feed => feed %>
              <%#= feed.subject.title %>
            <% end %>
          <% elsif feed.subject_type == 'Project' %>
            <%= link_to polymorphic_path(feed.subject) do %>
              <%= render "activities/project_feed", subject: feed.subject, :feed => feed %>
            <% end %>
          <% else %>
            <%= link_to polymorphic_path(feed.subject) do %>
              <%= render "/activities/project_record_feed", subject: feed.subject, :feed => feed %>
            <% end %>
          <% end %>
       <% end %>
    </div>

<% end %>

I got error message "undefined method `project_record_path' for #<#:0x007f9368c63f88>"

I know the path is wrong, because ProjectRecord belongs to Project.

I try to use "project_project_record_path" to replace "polymorphic_path(feed.subject)", but it can't find project_id and project_record's id.

new_project_project_record GET      /projects/:project_id/project_records/new(.:format)      project_records#new
edit_project_project_record GET      /projects/:project_id/project_records/:id/edit(.:format) project_records#edit
     project_project_record GET      /projects/:project_id/project_records/:id(.:format)      project_records#show

If I remove the link_to helper(project_record), only

  <%= render "/activities/project_record_feed", subject: feed.subject, :feed => feed %>

, dashboard/show page shows up, and other links work fine.

I want each ProjectRecord feed link to ProjectRecords/show page.
How to make this work?


Solution

  • To solve your routing problem you can use shallow routes:

    resources :projects do
      resources :project_records, shallow: true
    end
    

    This makes index/new/create actions stay nested inside Project, but show/update/destroy go to the top level, as if resources were not nested.