Selecting a subset of a table with DRY

Hello,

I have table called ‘listings.’ There are a certain combination of
properties which make a listing viewable (e.g., it is confirmed, has
been authorized, hasn’t expired, etc.). Each listing has one and only
one category.

I want to be able to do things like Listing.find_viewable(…) and
Category.find(…).viewable_listings, but I see no way to do this
without violating DRY in several places, or stepping all over AR’s toes.

My idea was to define a method in application.rb which returns the
appropriate SQL string that makes a listing viewable, call it
viewable_sql, and then put that where appropriate. However, I’d like
find_viewable to work just like find, except that it would modify the
parameters to find to incorporate those conditions.

Any thoughts or examples of something similar?

Thanks.


Jesse F. [email protected]
University of Chicago - NSIT Web Services
AIM: farmerje
Jabber: [email protected]
Phone: (773)363-1058

Hello Jesse,

2006/1/9, Jesse F. [email protected]:

My idea was to define a method in application.rb which returns the
appropriate SQL string that makes a listing viewable, call it
viewable_sql, and then put that where appropriate. However, I’d like
find_viewable to work just like find, except that it would modify the
parameters to find to incorporate those conditions.

Did you know that class methods of model objects are made available in
has_many/belongs_to and friends ?

So, if you do

class Listing
def self.viewables(options={})
options.merge(:conditions => [‘confirmed = 1 AND authorized = 1’])
self.find(:all, options)
end
end

Then, you can do

Category.listings.viewables(:order => ‘created_at DESC’)

Hope that helps !

Francois B. wrote:

end

Then, you can do

Category.listings.viewables(:order => ‘created_at DESC’)

Hope that helps !

François Beausoleil
http://blog.teksol.info/

That is nice. For the like I was defining has_many :viewable_listings
and then doing Category.find(some_category).viewable_listings. This
provides another nice perspective.

However, this doesn’t entirely solve my problem. It is two-fold, I
guess.

  1. Sometimes I want to find a specific viewable listing.
  2. Sometimes I want to find all viewable listings satisfying certain
    criteria.

The way I have it now is that basically the “is_viewable?” sort of logic
is duplicated for each of these. This will simplify my error handling
since the controllers searching for a specific entry will be expecting
an exception to be raised if there is an error, while ones requesting
multiple entries will expect the returned result to be false.

So, for example, I might do this:
def view
@listing = Listing.find_viewable(params[:id])
rescue

end

while elsewhere I might want

def category
@listings = Category.find_by_name(params[:name]).viewable_listings
unless @listings

end
end

or some such. Is there any way I can integrate these two things without
breaking AR and maintaining DRY? The logic is replicated once in
viewable_listings or equivalent and once in find_viewable.

Thanks again!


Jesse F. [email protected]
University of Chicago - NSIT Web Services
AIM: farmerje
Jabber: [email protected]
Phone: (773)363-1058

— quote —
Is there any way I can integrate these two things without
breaking AR and maintaining DRY? The logic is replicated once in
viewable_listings or equivalent and once in find_viewable.
— quote —

so just to make sure i understand this correctly, you want a single
method
to be able to return either a single viewable listing or multiple
viewable
listings depending on the argiments? sounds just like what
AR::Base.finddoes for you already, for the most part.

if you think about it, you’d basically be rewriting AR::Base.find with
hardcoded conditions (whatever makes a listing ‘viewable’). all this
would
do is save you from having to specify your conditions in the find call.

if you step back and think about it for a minute, this is the way you
would
normally do it.

def view
begin
@viewable_listing = Listing.find(params[:id], :conditions => “…”)
rescue RecordNotFound
# handle record not found exception here
end
end

def category
@viewable_listings = Category.listings.find(:all, :conditions =>
“…”)
end

with your idea, you want to be able to do:

def view
begin
@viewable_listing = Listing.find_viewable(params[:id])
rescue RecordNotFound
# handle record not found exception
end
end

def category
@viewable_listings = Category.listings.find_viewable(:all)
end

notice the only thing i’ve changed is the method name and removed the
:conditions, as the conditions would be handled within your custom
find_viewable method

class Listing < ActiveRecord::Base
def self.find_viewable(args)
conditions = “…”
# merge in your custom ‘viewable’ conditions into the arguments and
then
call AR::Base.find
self.find(args)
end
end

merging your custom conditions is beyond my abilities at the moment, but
i
think this is what you are after. you could probably take a look at the
source to AR::Base.find to figure it out.

hope this helps.