andy
andy

Reputation: 2399

Passing a symbol as a method?

I have this scope in a model called activity:

scope :today, where("DATE(qualify_date) = ?", Date.today)

and I have another separate model (user) that will use that to calculate some figures and I want to be able to use:

User.calls_for :today

that will then call theactivity model and the today scope but I can't figure out out to use the symbol provided to call that scope

The calls_for method will contain the following:

activities.*scope*.to_a.sum(&:calls).to_i

Upvotes: 1

Views: 207

Answers (4)

Matt
Matt

Reputation: 14038

Do activities belong to a user? If so you can just call it directly:

@user.activities.today

Keep in mind that your scope needs to be a lambda so that it reevaluates each request, or it will cache the date at which it was first called.

# Ruby 1.8
scope :today, lambda { where("DATE(qualify_date) = ?", Date.today) }

# Ruby 1.9+
scope :today, -> { where("DATE(qualify_date) = ?", Date.today) }

Upvotes: 1

dancow
dancow

Reputation: 3388

As already stated, #send is what you'll want to use. But you may want to consider using some meta programming...I'm guessing that besides the :today scope, you also have something like :yesterday, :two_weeks_ago, etc. scopes.

So, you can always do something like:

def calls_for(foo)
  activities.send(foo).sum(:calls).to_i
end


def method_missing(foo, *args, &block)
  if foomatch = foo.to_s.match(/^calls_for_(\w+)/)
    foo_scope = foomatch[1].to_s
    send(:calls_for, foo_scope)
  else
    super
  end
end

def respond_to?(meth, x=false)
  if meth.match(/^calls_for_(\w+)/)
    true
  else
    super
  end
end

Upvotes: 1

tomciopp
tomciopp

Reputation: 2742

You are going to want to use the send method, I also believe your call to #to_a is unnecessary since activities should return an ActiveRelation which is enumerable.

def calls_for scope = :today
  activities.send(scope).sum(&:calls).to_i
end

In the above method you can just call User.calls_for which will be the same as User.calls_for(:today). This will be pretty flexible for the future as you can now define multiple scopes and use the same method. i.e. calls_for(:yesterday)

Also define your scope as Matt has shown above so you don't run into the classic gotcha.

Upvotes: 5

spickermann
spickermann

Reputation: 106802

I am a little bit confused if you want to get activities for a special user or a list of all activities. If you want a to call it like this User.call_for(:today):

def self.calls_for(date)
  Activity.call(date)
end

If you want user.call_for(:today):

def calls_for(date)
  activities.call(date)
end

But is you see it would be easier just to write Activity.today or user.activites.today.

Upvotes: 0

Related Questions