Rails: создать метод для класса, который нуждается в информации от членов своего собственного класса? - PullRequest
0 голосов
/ 19 января 2011

Мне было интересно, можно ли сделать что-то вроде следующего:

Допустим, у меня есть модель Rails Foo с атрибутом базы данных value. Foo принадлежит_ Bar, Bar has_many Foos.

В моей модели я хотел бы сделать что-то вроде:

class Foo < ActiveRecord::Base

  belongs_to :bar

  def self.average
    # return the value of all foos here
  end

end

В идеале я хотел бы, чтобы этот метод возвращал значение, соответствующее области действия, из которой он был вызван, так что:

Foo.average # would return the average value of all foos

@bar = Bar.find(1)
@bar.foos.average # would return the average of all foos where bar_id == 1

Можно ли это сделать, и если да, то как? Спасибо!

1 Ответ

5 голосов
/ 19 января 2011

То, что у вас есть, будет работать, как есть, до тех пор, пока вы будете вызывать методы на self вместо Foo в теле метода average.При вызове методов в области действия Foo, self в теле этого метода будет назначено объекту области действия, а не Foo.Вот немного более конкретный пример:

# app/models/club.rb
class Club < ActiveRecord::Base
  # name:string
  has_many :people
end

# app/models/person.rb
class Person < ActiveRecord::Base
  # club_id:integer, name:string, age:integer
  belongs_to :club

  def self.average_age
    # note that sum and count are being called on self, not Person
    sum('age') / count
  end
end

Давайте посмотрим, что произойдет, когда мы создадим несколько клубов и людей:

$ rails console
Loading development environment (Rails 3.0.3)
irb(main):001:0> boys_club = Club.create(:name => 'boys')
irb(main):002:0> girls_club = Club.create(:name => 'girls')
irb(main):003:0> boys_club.people.create(:name => 'bob', :age => 20)
irb(main):004:0> boys_club.people.create(:name => 'joe', :age => 22)
irb(main):005:0> girls_club.people.create(:name => 'betty', :age => 30)
irb(main):006:0> Person.average_age
=> 24
irb(main):007:0> boys_club.people.average_age
=> 21
irb(main):008:0> Person.where("name LIKE 'b%'").average_age
=> 25
...