1

I wanted to know is it possible to do the following 2 things at once:

  • View all items with status published.
  • View items for current user with any status.

I have this code:

# Item model
scope :published, -> { where(status: 'published') }
scope :unpublished, -> { where.not(status: 'published') }
scope :by_user, -> (user_id) { where(user: user_id) }

# Item controller
def index
 @items = Item.published + Item.unpublished.by_user(current_user.id)
end

The problem is that @items are an Array, but I want ActiveRecord::Relation.

If you want to know why I need this, it's a simple answer:

@items.find(params[:id])
mamantoha
  • 343
  • 6
  • 10

3 Answers3

2

Based on the discussion in Rails: How to chain scope queries with OR instead of AND? I think you have at least four options:

1) Write a scope that combines your existing ones, something like:

scope :published_or_unpublished_by_user, -> (user_id) { where('status = ? OR (status != ? and user = ?)', 'published', 'published', user_id) }

2) Use a gem like squeel.

3) Use arel.

4) Wait for the .or syntax coming in Rails 5.

Community
  • 1
  • 1
Brian
  • 4,830
  • 2
  • 23
  • 29
2

Rails 4.x doesn't support OR or UNION queries yet, therefore I would suggest a new scope that combines the other scopes with subqueries (the database should be able to optimize them):

# in the model
scope :visible_for_user, ->(user) {
  where(
    'items.id IN (?) OR items.id IN (?)',
    Item.published, Item.unpublished.by_user(user.id)
  )
}

# in the controller
@items = Item.visible_for_user(current_user)

Please note that the above is a general solution when you want to union existing scope. In this specific example you might get a better performance with a optimized scope:

scope :visible_for_user, ->(user) { 
  where("items.status = 'published' OR items.user_id = ?", user.id)
}
spickermann
  • 89,540
  • 8
  • 92
  • 120
1

I see, you are trying to find unpublished items from current user. You can do it in my scope.

scope :current_user_not_published, ->(user_id) 
      {where('status != ? AND user = ?', 'published', user_id)}

Controller:

# Item controller
def index
 @published_items = Item.published
 @current_user_unpublished_utems = Item.current_user_not_published(current_user.id)
end

OR

#in this case it will be @items[0] published, @items[1] c.not_published

def index
  @items = [Item.published, Item.current_user_not_published(current_user.id)]
end
7urkm3n
  • 5,669
  • 4
  • 24
  • 46