首先让我为一个看似简单的问题道歉,但是对于rails,ruby和编程我是新手,我觉得我已经用尽了“New to Rails”教程。
这就是我反对的内容。
我有一个具有“has_many:through =>:company_reps”关系的用户模型和机构模型。
用户有基本字段(姓名,电子邮件,密码)(我正在使用devise)
机构有很多字段,但相关的字段是(client = boolean,lead = boolean,demo_date = date / time) 为了进一步复杂化,每个机构可以有一个或两个用户,但大多数只有一个。
我们正在为用户举办比赛,我需要根据demo_date字段和客户字段为每位用户奖励积分。
首先,我需要做的是给每个用户10个与客户机构相关的积分,除非该机构有2个用户,在这种情况下我需要给这两个用户各5分。
其次,我需要向所有用户提供1个与2012年2月之后具有演示日期的机构相关的点数。
我正在使用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
答案 0 :(得分:2)
更新(因为我的第一次尝试是错误地假设User has_one :institution
最简单的选择是对Institution
模型进行基本计算,以确定该机构有多少分数&#34;值得&#34;,然后对该值进行求和以计算用户&#34; s点。
# 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
将这些? :
语句压缩为单行。另请注意,我假设&#34;在2月和#34;之后从3月1日开始意味着&#34;&#34;。
检查零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
,这是一个非常棒的小方法。
就性能而言,这不是最理想的。一个基本的改进是记住结果:
# Institution
def points
@points ||= points_for_client + points_for_demo_date
end
# User
def points
@points ||= institutions.inject ...
end
因此,在同一请求中进一步调用points
不会重新计算该值。只要client
和demo_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
但是,确定何时重新计算该值将成为一个问题。
我的建议是尽可能简化并避免过早优化。这是一个相对简单的计算,因此它不会成为一个重大的性能问题,只要您没有大量的用户和机构或许多请求正在进行。
答案 1 :(得分:0)
积分累积到User
s,所以在User
类上添加方法调用似乎是有意义的,它会返回它们累积的点数。
我首先要编写一个方法,在每次调用时计算总点数,并进行一些单元测试以确保计算正确。我不会首先保存结果 - 取决于你有多少个对象,你需要计算点的频率等等,你可能根本不需要保存它。