Forum: Ruby on Rails Selecting a subset of a table with DRY

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
F7a2f59c93fae91cb2c9a44060b34a13?d=identicon&s=25 Jesse Farmer (vann)
on 2006-01-10 00:08
(Received via mailing list)
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 Farmer <farmerje@uchicago.edu>
University of Chicago - NSIT Web Services
AIM:    farmerje
Jabber: farmerje@im.uchicago.edu
Phone:  (773)363-1058
3dd4b52a0946bd698b1d1635a46ea3a3?d=identicon&s=25 Francois Beausoleil (Guest)
on 2006-01-10 01:29
(Received via mailing list)
Hello Jesse,

2006/1/9, Jesse Farmer <farmerje@uchicago.edu>:
> 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 !
F7a2f59c93fae91cb2c9a44060b34a13?d=identicon&s=25 Jesse Farmer (vann)
on 2006-01-10 01:56
(Received via mailing list)
Francois Beausoleil 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 Farmer <farmerje@uchicago.edu>
University of Chicago - NSIT Web Services
AIM:    farmerje
Jabber: farmerje@im.uchicago.edu
Phone:  (773)363-1058
A2c85dc5ee81b12e3cc0a6522e8d079d?d=identicon&s=25 Chris Hall (Guest)
on 2006-01-10 15:09
(Received via mailing list)
--- 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.
This topic is locked and can not be replied to.