2012-10-24 34 views
0

首先,讓我爲一個看似簡單的問題表示歉意,但對rails,ruby和編程新手我覺得我已經用盡了「New to Rails」教程。在Ruby和Rails中使用計算

這就是我所反對的。

我有一個「has_many:through =>:company_reps」關係的用戶模型和機構模型。

用戶有基本的字段(姓名,電子郵件,密碼)(我使用devise

該機構有許多領域,但相應的有(客戶端=布爾值,鉛=布爾值,demo_date =日期/時間) 使每個機構進一步複雜化可以有一個或兩個用戶,但大多數只有一個。

我們爲用戶舉辦比賽,我需要根據demo_date字段和客戶端字段向每個用戶頒發積分。因此,首先我需要做的是爲每個用戶提供10個與作爲客戶的機構相關的點數,除非該機構有2個用戶,在這種情況下,我需要給這兩個用戶各5分。

其次我需要給所有用戶1點涉及到具有2012年二月之後演示日期

我使用Ruby 1.9.2的機構來說,Rails 3.2.8和MySQL

  • 那麼,我該如何做到這一點?
  • 我應該創建一個新的表格和模型來存儲點,如果是的話我該如何保存計算?
  • 我應該把所有的計算都放在用戶或機構模型中嗎?

一如既往感謝您的幫助。

MySQL的機構信息

CREATE TABLE `institutions` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `state_id` int(11) DEFAULT NULL, 
    `company` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `clientdate` datetime DEFAULT NULL, 
    `street` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `city` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `zip` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `source` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `source2` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `demodate1` datetime DEFAULT NULL, 
    `demodate2` datetime DEFAULT NULL, 
    `demodate3` datetime DEFAULT NULL, 
    `client` tinyint(1) DEFAULT NULL, 
    `prospect` tinyint(1) DEFAULT NULL, 
    `alead` tinyint(1) DEFAULT NULL, 
    `notcontacted` tinyint(1) DEFAULT NULL, 
    `created_at` datetime NOT NULL, 
    `updated_at` datetime NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=7805 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

機構模式

class Institution < ActiveRecord::Base 
    attr_accessible :company, :phone, :assets, :clientdate, :street, :city, :state_id, :zip, :source, :source2, :demodate1, :demodate2, :demodate3, :client, :prospect, :alead, :notcontacted 
    belongs_to :state 
    has_many :users, :through => :company_reps 
    has_many :company_reps 

end 

用戶模型

class User < ActiveRecord::Base 
    # Include default devise modules. Others available are: 
    # :token_authenticatable, :confirmable, 
    # :lockable, :timeoutable and :omniauthable 
    devise :database_authenticatable, :registerable, 
     :recoverable, :rememberable, :trackable, :validatable 

    # Setup accessible (or protected) attributes for your model 
    attr_accessible :email, :password, :password_confirmation, :remember_me, :first_name, :last_name 
    # attr_accessible :title, :body 

    has_many :states, :through => :rep_areas 
    has_many :institutions, :through => :company_reps 
    has_many :rep_areas 
    has_many :company_reps 

    def name 
    first_name + " " + last_name 
    end 


end 

公司代表型號

class CompanyRep < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :institution 
end 

回答

2

更新(因爲我的第一次嘗試是錯誤假設User has_one :institution

最簡單的辦法是做對Institution模型的基本計算建立該機構有多少個是「值得」,然後和那值來計算用戶的積分。

# Institution 
def points 
    points_for_client + points_for_demo_date 
end 

private 

def points_for_client 
    if client? 
    10/users.count 
    else 
    0 
    end 
end 

def points_for_demo_date 
    if demo_date.present? && demo_date >= Date.new(2012, 3, 1) 
    1 
    else 
    0 
    end 
end 

請注意,如果你願意,你可以凝結這些if語句轉換爲單行與三元運算符? :。另外請注意,我以爲「鐵後布魯裏「來表示」從3月1日起「。

demo_date的支票也是一個口味問題。就拿從

# Verbose, but IMO intention-revealing 
demo_date.present? && demo_date >= Date.new(...) 

# Perhaps more idiomatic, since nil is falsy 
demo_date && demo_date >= Date.new(...) 

# Take advantage of the fact that >= is just another method 
# Concise, but I think it's a bit yuk! 
demo_date.try :>=, Date.new(...) 

現在,每個機構都值得一定的點數,這是相當簡單的你挑總結起來:

# User 
def points 
    institutions.inject(0) {|sum, institution| sum + institution.points } 
end 

退房the docs for inject如果你不熟悉它,這是一個漂亮的小方法。

就性能而言,這是不理想的。一個基本的改進是memoize的結果:

# Institution 
def points 
    @points ||= points_for_client + points_for_demo_date 
end 

# User 
def points 
    @points ||= institutions.inject ... 
end 

,這樣在相同的請求points還呼籲不要重新計算值。這沒關係,只要clientdemo_date不改變而User對象還活着:

some_user.points #=> 0 
some_user.institution.client = true 
some_user.points #=> 0 ... oops 

User對象將被重新創建下一個請求,所以這可能不是一個問題(這取決於如何這些領域改變)。

你也可以一個points字段添加到User,從而節省值在數據庫中,使用原始版本的update_points方法,而不是

def update_points 
    self.points = institutions.inject ... 
end 

然而,工作了的時候,重新計算值那麼將成爲一個問題。

我的建議是保持儘可能簡單,避免過早優化。這是一個相對簡單的計算,所以它不會是一個很大的性能問題,只要你沒有大量的用戶和機構或大量的請求正在進行。

+0

哇...完美。非常感謝。 – DaveG

+0

還有一個問題。當我做一個rails控制檯來嘗試代碼。我會做一些像u = User.find(1)。然後u.points我得到未定義的方法'客戶端?' 。這是由於用戶擁有多個機構嗎? – DaveG

+0

啊,對不起,我誤解了這個問題,我正在研究'User has_one:institution'這個假設。我會更新我的答案。 –

0

積分累積到User S,所以它似乎有道理對User類返回他們已經積累的點數添加一個方法調用。

我只是寫一個方法,每次調用時計算總點數,並使用一些單元測試來確保計算是正確的。起初我不會保存結果 - 取決於您擁有多少個對象,需要多長時間計算點數等等,您可能根本不需要保存它。