0

首先让我为一个看似简单的问题道歉,但是对于 Rails、Ruby 和编程的新手,我觉得我已经用尽了“Rails 新手”教程。

这就是我所反对的。

我有一个用户模型和机构模型,它们具有“has_many :through => :company_reps”关系。

用户具有基本字段(姓名、电子邮件、密码)(我正在使用devise

该机构有许多字段,但相关的字段是(客户 = 布尔值,潜在客户 = 布尔值,演示日期 = 日期/时间)更复杂的是,每个机构可以有一个或两个用户,但大多数只有一个。

我们正在为用户举办比赛,我需要根据 demo_date 字段和 client 字段为每个用户奖励积分。

所以首先我需要做的是给每个用户 10 分,这与作为客户的机构相关,除非该机构有 2 个用户,在这种情况下,我需要给这两个用户每个 5 分。

其次,我需要给与 2012 年 2 月之后有演示日期的机构相关的所有用户 1 分。

我正在使用 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
4

2 回答 2

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

如果您不熟悉它,请查看文档,这是一个漂亮的小方法。inject

就性能而言,这是次优的。一个基本的改进是记住结果:

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

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

这样points在同一请求中的进一步调用就不会重新计算该值。只要clientand在对象还活着的时候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

但是,确定何时重新计算该值将成为一个问题。

我的建议是使其尽可能简单并避免过早优化。这是一个相对简单的计算,所以它不会是一个大的性能问题,只要你没有大量的用户和机构或大量的请求。

于 2012-10-24T17:20:45.400 回答
0

积分累积到s,因此在类上添加一个方法调用,返回他们累积的积分数User似乎是有意义的。User

我将首先编写一个方法来计算每次调用时的总分,并进行一些单元测试以确保计算正确。我一开始不会保存结果——取决于你有多少对象,你需要多久计算一次点等等,你可能根本不需要保存它。

于 2012-10-24T16:13:33.560 回答