Brian
Brian

Reputation: 143

Filtering rails model with unknown data

I am grabbing a list of open buckets for a particular user with the following code.

@open_buckets = Buckets.order("buckets.id ASC").where(:user_id => @user.id)

There is also a concept of private buckets for the user. I only want the private buckets to be returned when the logged in user is the owner of the bucket. The private field is a boolean. Can I somehow change my query so all users get the public buckets and only the owners get their private buckets and public buckets?

The only thing I thought of was to check to see if the logged in user was the same as the user whose buckets are being requested and do a different query. Something like below.

if :session["user_id"] => :user_id
    @open_buckets = Buckets.order("buckets.id ASC").where(:user_id => @user_id)
else
    @open_buckets = Buckets.order("buckets.id ASC").where(:user_id => @user_id).where(:private => true)

Thanks

Upvotes: 0

Views: 321

Answers (2)

jefflunt
jefflunt

Reputation: 33954

A named_scope (or just scope in Rails 3) can do it.

class Bucket
  ...

  named_scope :visible_buckets_for, lambda {|user| { :conditions=>["private = 'f' OR (private = 't' and user_id = ?)", current_user.id], :order=>"buckets.id ASC" } }

Where 'current_user' is whatever method you have to retrieve the id of the currently logged in user, and 't' is a DB-specific representation of a true value. Some DB's use "true", or any non-zero number.

Then you call it like:

 > Bucket.visible_buckets_for(current_user)
=> [<#Bucket1>, <#Bucket2>, <#Bucket3> ... ]

...which is an array of Bucket objects, sorted by id.

You can pass any user to that named scope, in case you need to find this out for more than just the current user.

Upvotes: 0

bricker
bricker

Reputation: 8941

Well, although I disagree with using one view (or one list/partial, more specifically) to display two different types of information, here is a way you could do what you're looking for:

@buckets = Buckets.order("buckets.id ASC").where(:user_id => @user_id, :private => false)
@buckets += @buckets.where(:private => true) if current_user.id == user.id

You could also create some cool scopes to handle this semi-complex logic in the model, where it should be, and also utilize your associations more fully:

@user = User.find(params[:user_id])
@buckets = @user.buckets.public
@buckets += @user.buckets.private if @current_user == @user
respond_with @buckets = @buckets.order("buckets.id asc")

and the Buckets model:

scope :public, where(:private => false)
scope :private, where(:private => true)

As a side note, model class names should always be singular. You have Buckets in your example, so if that's not a typo then I recommend going back and changing it if it's practical to do so. It will cause confusion further down the line, especially for future developers of your application.

Upvotes: 2

Related Questions