2013-04-18 8 views
2

Это мой сценарий:атрибута ActiveRecord зависит от расчета другой модели

class User < ActiveRecord::Base 
    has_many :things 
    # attr_accessible :average_rating 
end 

class Thing < ActiveRecord::Base 
    belongs_to :user 

    has_one :thing_rating 
end 

class ThingRating < ActiveRecord::Base 
    belongs_to :thing 

    attr_accessible :rating 
end 

Я хочу иметь атрибут в моей модели пользователя, который имеет средний расчет его соответствующий ThingsRating.

Какова была бы лучшая практика для управления этим?

Благодаря

ответ

1

Простой способ:

class User < ActiveRecord::Base 
    has_many :things 

    def avg_rating 
    @avg_rating ||= average(things.map(&:thing_rating)) 
    end 

    private 
    def average(values) 
    values.inject(0.0) { |sum, el| sum + el }/arr.size 
    end 
end 

Это прекрасно, как стартер. Но если у вас немного трафик, вы можете столкнуться с проблемами масштабирования.

После этого вам придется реорганизовать это, чтобы избежать запроса SQL к вещам каждый раз, когда вы вызываете метод для другого пользователя.
Вы могли бы иметь несколько possibilites:

  • Добавление поля в базе данных пользователя, avg_rating, которая будет обновляться по ThingRating, когда он создан или обновлен.
  • Используйте базу данных memcached или redis для кэширования значения и аннулирования кеша при каждом обновлении или создании ThingRating.

Эти решения, конечно, не являются исчерпывающими. И вы могли бы найти другие, которые лучше соответствовали бы вашим потребностям.

+0

Спасибо, я решил добавить новое поле avg_rating, чтобы избежать проблем с масштабированием. –

2

Может быть, вы можете воспользоваться соотношением не уверен, но вы можете попробовать это

class User < ActiveRecord::Base 
    has_many :things 
    has_many :thing_ratings, through: :things 

    # attr_accessible :average_rating 

    def avg_rating 
    @avg_rating ||= thing_ratings.average("thing_ratings.rating") 
    end 
end 
Смежные вопросы