0

I have a selection box in a view that allows a user to pick a user to share something with.

<%=
  f.collection_select :user_id, 
    @users, 
    :id, 
    :email, 
    {prompt: 'Select a User to Share with'}, 
    class: 'form-control'
%>

I don't want the already picked people to show in the list.

I am able to isolate the users in ActiveRecord::Relation objects, but I cannot figure out how to isolate just the ones that need to show up in the selection:

None of these Relations come straight off of tables.

If my existing Relations are "all_users" and "already_shared_with_users" how do I do the equivalent of:

select
  allu.user_id
from
  all_users allu
  left outer join already_shared_with_users alsu
    on alsu.user_id = allu.user_id
group by
  allu.user_id
  , alsu.user_id
having
  alsu.user_id is null

basically returning a Relation of the NOT already-shared-with users?

Here's what I've tried:

I've tried joins, but they don't work because I'm not using tables, nor associations:

potential_sharing_users =
  all_users
  .joins("already_shared_with_users")
    .where("already_shared_with_users" => { id: nil })

User class scopes won't suffice because the already_shared_with_users relation requires knowing the parameter id value of the thing I'm sharing (not the user) passed from the index view, and I'm not on the user view anyhow.

The one thing that I've held off on is going straight to SQL, especially since I don't know how yet and I wanted to try it the Rails way.

Speaking of, I found the following which will cover that part, I just need to pass in the aforementioned parameter: Rails Activerecord Relation: using subquery as a table for a SQL select statement and http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-from

I'm new to Rails and Ruby, so I there's something obvious I'm missing here. Perhaps I shouldn't with Relations and collection_select since I'm not trying to delete anything from a table, just display it in a limited fashion. I did find http://guides.rubyonrails.org/form_helpers.html#making-select-boxes-with-ease which should shed some light on alternatives.

Thanks.

Community
  • 1
  • 1
jetimms
  • 417
  • 1
  • 5
  • 23
  • Found SO answer to another related question: http://stackoverflow.com/questions/9540801/combine-two-activerecordrelation-objects that suggests using merge() and not() or none_of() with search() so I will give those a shot. – jetimms Dec 24 '14 at 02:19

1 Answers1

1

You haven't provided the model names in your model, so I shall include sample ones in my response.

  • Model 1: User; the one you want the entries from

  • Model 2: SharingWithUser; includes user_id

To get users that aren't in SharingWithUser, you can either do this:

user_ids = SharingWithUser.where(parameter_id: some_value).pluck(:user_id)
users = User.where.not(id: user_ids) # OR User.where("id NOT IN (?)", user_ids)

Or you can do this:

t2 = SharingWithUser.table_name
users = User.where("#{User.table_name}.id NOT IN (
  SELECT user_id FROM #{t2} WHERE #{t2}.parameter_id = #{some_value}
)")

If some_value somehow depends on URL params, then the former method will better protect you against SQL injection.

SHS
  • 7,651
  • 3
  • 18
  • 28
  • Thanks. That worked perfectly. I briefly attempted to use select/collect after googling pluck (since I had never come across it until your answer) because they return full Relations. However I couldn't get select/collect to return a full user object, only the field user_id (or similar), and after realizing your solution was giving me the Relation anyhow, I decided it was the better solution. – jetimms Dec 24 '14 at 06:00