has_many option explanation

I am maintaining an application that has an account model which has many payments. So the account model has a has_many relationship as shown below:

class Account < ActiveRecord::Base ....   has_many :payments, :order => "created_at ASC" do     def charge(amount, paying_for)       Payment.charge(proxy_owner, amount, paying_for)     end

    def commit(action, amount, paying_for)       Payment.commit(proxy_owner, action, amount, paying_for)     end

    def gift(days = nil)       Payment.gift(proxy_owner, days)     end   end ..... end

This may be an RoR 101 question, but why would someone define methods in a has_many block? Can't this be simply called as:

account_inst.payments.charge(amount, paying_for) for example?

I do not understand what is the benefit of defining (or proxying ) class methods belonging to the many side of this relationship in this manner?

Thanks for your time.

Bharat

I am maintaining an application that has an account model which has many payments. So the account model has a has_many relationship as shown below:

class Account < ActiveRecord::Base .... has_many :payments, :order => "created_at ASC" do def charge(amount, paying_for) Payment.charge(proxy_owner, amount, paying_for) end

def commit\(action, amount, paying\_for\)
  Payment\.commit\(proxy\_owner, action, amount, paying\_for\)
end

def gift\(days = nil\)
  Payment\.gift\(proxy\_owner, days\)
end

end ..... end

This may be an RoR 101 question, but why would someone define methods in a has_many block? Can't this be simply called as:

It's nicer to write some_account.payments.gift than it is to write Payment.gift(some_account). You get the association scoping for free which can help you avoid mistakes and make things more readable.

account_inst.payments.charge(amount, paying_for) for example?

That is precisely what the association extension methods that have been defined allow you to do. One trick that is not well known enough is that if foo is a class method on payments then you can call account_inst.payments.foo() and it will call the class method foo except that everything will be scoped to only act on those payments belong to foo. This won't work with the existing charge method since it requires an account as its first parameter.

Fred

Thanks Fred. You wrote:

"This won't work with the existing charge method since it requires an account as its first parameter."

Was this an oversight since the first parameter of the existing charge method is amount as shown below?

   def charge(amount, paying_for)       Payment.charge(proxy_owner, amount, paying_for)     end

Nice explanation.

Regards,

Bharat

Thanks Fred. You wrote:

"This won't work with the existing charge method since it requires an account as its first parameter."

Was this an oversight since the first parameter of the existing charge method is amount as shown below?

No - what i meant that the charge method you would get for free on the
payments association (because of the existence of Payment.charge)
wouldn't do the write thing.

Fred