Reputation: 41855
I have a database of Item
s. Each items belongs_to
a User
. Each item has a visibility
and status
field. In order to be searchable, an item must satisfy the following rules:
status must be :available
AND
(visibility must be :everyone
OR
(visibility must be :friends AND user_id must be in current_user.friends)
)
In other words, you see all available and public items, and you see the "private" items of your friends.
How can I retrieve the items that follow this condition ?
I have tried the following:
class Item < ActiveRecord::Base
belongs_to :user
attr_accessible :description, :photo, :title, :user_id, :visibility
#...
scope :searchable, lambda { |user|
where('status IN ? AND (visibility IN ? OR (visibility IN ? AND user_id IN ?))',
[:available, :lent],
[:everyone],
[:friends],
user.friends)
}
end
And in my controller:
@items = Item.searchable(current_user)
But I have an error:
There is no paren around IN generated clauses
ActiveRecord::StatementInvalid in Items#search
SQLite3::SQLException: near ",": syntax error: SELECT "items".* FROM "items" WHERE (status IN 'available','lent' AND (visibility IN 'everyone' OR (visibility IN 'friends' AND user_id IN 'foo')))
Upvotes: 0
Views: 3277
Reputation: 29599
I personally prefer declaring a class method over scope with a lambda. I think it's easier to read. plus, it's easier to set a default.
def self.with_status(statuses)
where(status: statuses)
end
def self.visible_to_friends_of(user)
where('visibility = ? OR (visibility = ? AND user_id IN (?))',
'everyone',
'friends',
user.friends
)
end
def self.searchable(user)
with_status([:available, :lent]).visible_to_friends_of(user)
end
Upvotes: 4
Reputation: 540
i think you should use thinking_sphinx gem for this.
define_index do
indexes title
indexes description
indexes uploads.file_file_name, :as => :upload_file_name
indexes uploads.file_content_type, :as => :upload_file_content_type
has :id
has price
has user_id
has created_at
has purchase_count
has images.photo_file_size
has tags.id, :as => :tag_id, :facet => true
has tags.parent_id, :as => :tag_parent_id, :facet => true
has "state='active'", :as => :active, :type => :boolean, :facet => true
has "count(images.id) > 0", :as => :has_image, :type => :boolean
has "sum(uploads.file_file_size)", :as => :total_size, :type => :integer
where "state in ('active', 'pending')"
set_property :delta => true
set_property :morphology => 'stem_en'
set_property :min_prefix_len => 3
set_property :enable_star => true
end
to satisfy your requirements you can use has condition or where clause. you find out more on Click here
Upvotes: 0
Reputation: 41855
Well, I didn't know you have to put the paren yourself around the ?
s (as you say @MurifoX)
scope :searchable, lambda { |user|
where('status IN (?) AND (visibility IN (?) OR (visibility IN (?) AND user_id IN (?)))',
[:available, :lent],
[:everyone],
[:friends],
user.friends)
}
I am still open if there is a better way to implement this behavior.
Upvotes: 2