views:

132

answers:

5

I'm looking to define a method that lets me pass options; something like:

@user.tasks(:completed => true)

I thought something like this would work in my user model (but it's not):

User.rb model

  def tasks(options)
    tasks.find(:all, options)
  end

How would I define the method correctly to let me use @user.tasks(:completed => true)?

+1  A: 

what you need is:

options[:conditions] in your method

ennuikiller
Thank you so much!
sjsc
your very welcome!
ennuikiller
+3  A: 

This is basically how I'd do it:

def tasks options={}
  unless options[:something].blank? 
    # do stuff
  end
end

There are some different ways to pass options, but you definitively want to pass a hash with a default value (so that you can call the method without options).

In your case the following should address what you want to do:

def tasks options={}
  Task.find(:all, options[:conditions])
end

Edit: and then call it @thing.tasks( {:conditions => "blah"} )

I haven't tested but it should be ok

Edit 2: But like EmFi said it's not optimal to do this. Consider using an association instead. You'll be able to go @thing.tasks.find(:all, :conditions => {blah})

marcgg
This is perfect. I just got it working from your example. I originally had @thing.tasks.find(:completed => true), so I think that might be a better way to go about it. Thank you so much!
sjsc
+2  A: 

Why would you associate a find all on another model with an instance method? I could understand if it was a relation and the find required find options based on the calling record. But there's ActiveRecord Associations for that.

Then there's ActiveRecord::Base#all(options) which is an alias for Task.find(:all, options)

Together make things simpler:

class User < ActiveRecord::Base
  has_many :tasks
end

@user.tasks.all(:conditions => {:completed => true})
EmFi
Yeah, I totally understand my clumsy way of going about it. I revised it based on your recommendation. Thanks so much EmFi.
sjsc
+4  A: 

Does User have a has_many :tasks association? That seems to be what you're after here. In that case Rails provides finders for you, which you can access like this:

@user.tasks.find :all, :conditions => { :completed => true }

Or even shorter:

@user.tasks.all :conditions => { :completed => true }

If that's not terse enough and you always want to use a particular condition, try a named scope:

# In your Task model:    
named_scope :completed, :conditions => { :completed => true }

# Then you can just call...
@some_user.tasks.completed # => Only completed Tasks for @some_user
Jordan
named_scope is a much cleaner solution I'm seeing. Thank you so much Jordan!
sjsc
A: 

Activerecord provides a method called with_scope, so to pass any additional conditions

@user.tasks(:completed => true)

you can define the task method as

def tasks(options={})
  with_scope :find => options
    User.all :order => 'id desc'
  end
end

and this will merge any hash passed as options parameter with the actual find

The only caveat is you need to modify your method call slightly

@user.tasks(:conditions => {:completed => true})

or to something like

@user.tasks(:select => 'username')

But if there is an association between user and tasks model then I would do what Jordan has in his post

nas