29

I'm not sure if my question is worded correctly.

I have three models: User, Item, and UserItem.

user has_many :user_items
user has_many :items, through :user_items

item has_many :user_items
item has_many :users -> {uniq}, through :user_items
item belongs_to :user

user_item belongs_to :user
user_item belongs_to :item

I need a way to see if a user has an item to make if statements in my item views But here's the catch, user_items have enum status: [ :pending, approved]. So I need to see if a current_user has a certain :pending item.

For example when a user visits item1's view page I have the item_controller's show action declare @item = Item.find_by_id(params[:id]). But then what can I do with this @item to see if a user has this item?

user4584963
  • 2,403
  • 7
  • 30
  • 62

4 Answers4

46

Try:

current_user.items.exists?(params[:id])

Or

current_user.items.exists?(@item.id)
Kevin Sylvestre
  • 37,288
  • 33
  • 152
  • 232
lei liu
  • 2,735
  • 1
  • 16
  • 18
7

Extending @lei-liu's answer here. One can find if the record exists among the many or not, through: current_user.items.exists?(params[:id])

At the same time, exists? allows one to filter through the columns besides id, and also allows for more complicated conditions, like the following:

current_user.items.exists?('id > 3')
current_user.items.exists?(name: 'some_name')
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
0

But then what can I do with this @item to see if a user has this item?

I think what you are missing here is model methods. For example, if you added a method to the Item model called belongs_to_user_in_pending_state, you'd be able to call @item.belongs_to_user_in_pending_state(current_user) anywhere you need it.

def belongs_to_user_in_pending_state(user)
  if self.user_items.pending.select {|s| s.user == user}.count > 0 
    return true
  else
    return false
  end
end
tkz79
  • 95
  • 10
  • This wasn't written to be something to copy and paste, it was written as an example to show the OP how to write and use a model method... and how to use his pending enumerator. The select call is a little wasteful given the uniq limitation, but someone else has already shown how to check if something exists. Way to hate without offering anything of value @AndreyDeineko. – tkz79 Apr 08 '16 at 16:02
  • 1
    1) you do not need `self`. 2) `select` would load the whole pending user_items collection into memory prior evaluating the block, thus, having tons records in collection it could potentially overwhelm the memory. 3) in this case you do not need to `return`. 4) you could just leave the `user_items.pending.select {|s| s.user == user}.count > 0` since it will already return the boolean value. 5) sorry for the form of my first comment - it was the very morning - apologies – Andrey Deineko Apr 08 '16 at 16:22
  • @AndreyDeineko You mentioned a "conventional" way to accomplish this. What would that be? – user4584963 Apr 08 '16 at 16:28
  • @user4584963 by the unconventional I meant the wrong use of `return` keyword here. – Andrey Deineko Apr 08 '16 at 16:32
  • @AndreyDeineko - 1+2 - I thought this was a good way to cut down the memory needs - we should only be fetching the user_items for that item, and only those that are pending... I did not know the self was unnecessary!! 3) the return habit comes from C when i took comp sci many years ago - before getting out of programming for over a decade. 4) Was thinking to set him up for more complicated functionality - agreed for this case! 5) All Good... Thanks for returning to clarify! Always enthusiastic to learn the better way! – tkz79 Apr 08 '16 at 19:20
-1

1) Add a scope to User_item class

scope :pending, -> {where status: 'pending'}

2) Use that scope in an instance method of Item class:

def is_pending_with_someone?
  self.user_items.pending.count > 0
end

Then you can use

if @item.is_pending_with_someone? 
  ...
GabrieleF
  • 124
  • 1
  • 5
  • 1
    I believe enum automatically adds scope – user4584963 Apr 08 '16 at 15:14
  • i don't think you want a count query. if you're just checking for existence using `.exists?` would give you a `SELECT ... LIMIT 1` which would stop once a match was found. – drewish Jan 29 '18 at 15:32