ruby-on-railspublic-activity

Scoping/Combining collections and ordering them ( Public Activity Gem on rails 4)


I am using the Public Activity Gem to create a notification system of sorts.Before I state my problem, I will provide the relevant code:

The controller action for Activities:

 def index
    @activities1 = PublicActivity::Activity.where(owner_id: current_user.articles, owner_type: "Article" )
    @activities2 = PublicActivity::Activity.where(owner_id: current_user.id , owner_type: "User")
    @activities  = @activities1 + @activities2
    @activities.sort_by{ |a| a[:created_at] }
  end

The View for activities#index

<% @activities.each do |activity| %>
   <%= render_activity activity %>
<% end %>

My aim is to have a collection of all relevant Activities that I want to display on the index view. However, something like the following happens:

1) Activity filler text(Created June 1) (Owner: Article)
2) Activity filler text (Created June 3) (Owner: Article)
3) Activity filler text (Created June 4) (Owner: Article)
4) Activity filler text (Created June 1) (Owner: User)
5) Activity filler text (created June 2) (Owner: User)

First, the activities with the owner Article are rendered, then after that, the activities with the owner User are rendered. I would like them all to be rendered in order(:created_at) and preferably in descending order, despite what their owner type is. Is there a better way to achieve this?


Solution

  • You could combine the two queries into one single query and let database do the sort thing.

    What you need is do a OR query.

    If you are using Rails 5 (beta or rc), you could use or method to achieve that:

    PublicActivity::Activity.where(owner_id: current_user.articles, owner_type: "Article" ).
      or(PublicActivity::Activity.where(owner_id: current_user.id , owner_type: "User")).order(id: :desc)
    

    If you are using an older version of Rails, you could use powerful Arel to do an Or query. In your case, here is the code:

    PublicActivity::Activity.where(article_activities.or(user_activities)).order(:id, :desc)
    
    def arel_table
      PublicActivity::Activity.arel_table
    end
    
    def article_activities
      arel_table[:owner_id].in(current_user.acticles.map(&:id)).
        and(arel_table[:owner_type].eq("Article"))
    end
    
    def user_activities
      arel_table[:owner_id].eq(current_user.id).
        and(arel_table[:owner_type].eq("User"))
    end
    

    You could refactor this to your PublicActivity::Activity model.