views:

118

answers:

2

I have a method that does a paginated find call like..

1

coll = paginate(:all, lambda {{:conditions => ['status = ? AND expires < ?', 'a', DateTime.now]}}, :select => Constants::POST_FIELDS,
                   :order => 'posts.ratings DESC', :include => [{:poster => :poster_friends}, :category], :per_page => Constants::LISTINGS_PER_PAGE,
                   :page => page)

When this call runs it simply ignores the conditions in the generated query.

2

If I try it in a named_scope I get an error like..

named_scope :featured_all, lambda {{:conditions => ['status = ? AND expires < ?', 'a', DateTime.now], order => 'posts.ratings DESC', :include => [{:poster => :poster_friends},  :category],
            :select => Constants::POST_FIELDS}}

The named-scope error :

/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.5/lib/active_support/core_ext/hash/keys.rb:47:in `assert_valid_keys'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2101:in `with_scope'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:113:in `__send__'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:113:in `with_scope'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:174:in `method_missing'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:188:in `load_found'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:166:in `proxy_found'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:109:in `is_a?'
    /usr/lib/ruby/gems/1.8/gems/hirb-0.3.1/lib/hirb/formatter.rb:78:in `determine_output_class'
    /usr/lib/ruby/gems/1.8/gems/hirb-0.3.1/lib/hirb/formatter.rb:48:in `format_output'
    /usr/lib/ruby/gems/1.8/gems/hirb-0.3.1/lib/hirb/view.rb:213:in `render_output'
    /usr/lib/ruby/gems/1.8/gems/hirb-0.3.1/lib/hirb/view.rb:126:in `view_output'

For #1. What am I doing wrong, why is it ignoring the conditions?

For #2 Why this error? And also, how can I pass the :page and per_page parameter to limit the query in the named_scope.

Thanks

A: 

Your named scope is missing a : before your order key. That might be blowing up the named scope. Otherwise, it looks fine.

That said, you don't need to use a lambda to get records relevant to the current time. Your database provides methods that do similar. For example, if you are using MySQL, you can use:

named_scope(:featured_all, {
  :conditions => "status = 'a' AND expires < UTC_TIMESTAMP()",
  :order => 'posts.ratings DESC',
  :include => [{:poster => :poster_friends}, :category],
  :select => Constants::POST_FIELDS
})

UTC_TIMESTAMP() is a MySQL-specific function that returns the current date and time in UTC (which Rails should be storing your DateTimes as already).

Chris Heald
I would rather not use a db specific code here. Any other option or am I fine without the lambda? You are right about the :order. Thanks!
badnaam
If you want to avoid DB-specific code, you'll need to use the lambda. It'll work without the lambda in development, but it'll get stuck in production, where model classes aren't reloaded per-request.
Chris Heald
+1  A: 

Your use case does not warrant a named_scope. You can write a regular finder as follows:

coll = paginate(:select     => Constants::POST_FIELDS,
                :conditions => ['status = ? AND expires < ?', 'a', DateTime.now],
                :include    => [{:poster => :poster_friends}, :category],
                :order      => 'posts.ratings DESC',  
                :per_page   => Constants::LISTINGS_PER_PAGE,
                :page => page)

The paginate method is equivalent to all, so you don't have to supply the :all result-set scope qualifier to the paginate method.

The time value is calculated upon the execution of the query. This is unlike a named_scope, where you have to use a lambda for the same effect.

If you need to use the named_scope then do the following:

named_scope :featured_all, lambda {{
                :select     => Constants::POST_FIELDS,
                :conditions => ['status = ? AND expires < ?', 'a', DateTime.now],
                :include    => [{:poster => :poster_friends}, :category],
                :order      => 'posts.ratings DESC'
               }}

Now you can use the named_scope as follows

Post.feature_all.paginate(:per_page => Constants::LISTINGS_PER_PAGE, 
                          :page => page)
KandadaBoggu
Thanks, good to know the time value is calculated upon query execution! The finder works just fine. The named scope crashed with an sql error message complaining about invlid attribute categories.id, I guess there is some sort of confusion in named scope if the :select clause contains an assocation.id or any other column with the same name? I have :select => 'posts.id, categories.id'
badnaam
What is the SQL printed with the error message?
KandadaBoggu
You have to use an alias (e.g.: `categories.id AS categories_id` ) while referring to joined tables in the `SELECT` clause.
KandadaBoggu