我正在尝试考虑允许用户在不创建帐户的情况下创建数据库对象的最佳方法,然后在他们决定注册时将这些对象与用户的帐户相关联。我将描述一个示例应用程序,我希望它如何表现,以及我提出的方法。我正在寻找对我的方法的批评/改进,或者是我和你们其中一位程序员的更好方法。
假设我们有一个名为意见箱的Rails应用程序。此应用程序允许用户访问该站点并输入建议。 Suggestion
需要说明和电子邮件地址。用户无需登录。以下是型号:
应用程序/模型/ suggestion.rb
class Suggestion < ActiveRecord::Base
# == DB Columns
# id :integer
# user_id :integer
# description :text
# email :string
belongs_to :user
validates :description, :email, :presence => true
end
应用程序/模型/ user.rb
class User < ActiveRecored::Base
# == DB Columns
# id :integer
# name :string
# email :string
has_many :suggestions
validates :name, :email, :presence => true
end
Frank来到Suggestion Box申请并提出建议。第二天弗兰克进入另一个。如果我们向Rails控制台询问所有建议,我们将得到这个:
# rails console
Suggestion.all
=> [#<Suggestion id: 1, user_id: nil, email: "frank@example.com", description: "Don't worry">,
#<Suggestion id: 2, user_id: nil, email: "frank@example.com", description: "Be happy">]
第三天,弗兰克决定咬紧牙关并注册一个帐户。然后他创建了另一个建议。此时如果我们向控制台询问User
个对象,我们会得到Frank:
# rails console
User.all
=> [#<User id: 1, name: "Frank", email: "frank@example.com" >]
如果我们要求弗兰克的建议,我们会得到所有3条建议:
# rails console
frank = User.last
=> [#<User id: 1, name: "Frank", email: "frank@example.com" >
frank.suggestions
=> #<ActiveRecord::Associations::CollectionProxy [#<Suggestion id: 1, user_id: nil, email: "frank@example.com", description: "Don't worry">,
#<Suggestion id: 2, user_id: nil, email: "frank@example.com", description: "Be happy">,
#<Suggestion id: 3, user_id: nil, email: "frank@example.com", description: "Don't worry be happy now!">]
现在我们如何在弗兰克和他过去的建议之间自动建立这种联系?
当未登录的用户提交会话时,我可以在cookie中存储关于创建的建议的指示符。然后,当他们注册时,我可以使用此信息查找建议并将其分配给用户。
我真的不喜欢这种方法,因为当用户访问多个设备时它会崩溃。
创建回调后当用户注册时,我可以运行一个看似如下的创建回调:
应用程序/ models.user.rb
class User < ActiveRecored::Base
...
after_create :assign_suggestions
def assign_suggestions
suggestions = Suggestion.where(:user_id => nil, :email => self.email)
suggestions.each do |s|
s.user = self
s.save
end
end
end
我真的很喜欢这种方法,但有一个主要的缺点。如果Frank在未登录时创建第四个建议,则不会将其添加到其用户对象中。为了解决这个问题,我可以在Suggestion
类上编写一个可以检查匹配电子邮件的回调。
应用程序/模型/ suggestion.rb
class Suggestion < ActiveRecord::Base
...
after_create :assign_users
def assign_users
if self.user.present?
user = User.where(:email => self.email).first
if user
self.user = user
end
end
end
end
这非常好,但如果Frank使用不同的电子邮件地址创建建议(可能会发生,我有很多),那么该建议将不会与Frank的用户对象相关联。
你们对方法#2有什么看法? (好的或坏的)除此之外还有另一个技巧我可以用Frank将他与其他电子邮件地址建议联系起来吗?你能想到一种比我更好的方法吗?
感谢您的建议!
答案 0 :(得分:0)
您似乎正在尝试一次解决两个方案:分配用户是您的主要问题,并将多个电子邮件地址处理到一个帐户。
email address
字段在两个模型中重复。最初我建议保留User
中的电子邮件地址,并创建匿名(无名称)User
,然后从那里构建。这将改变您的Suggestion
创建过程,因为您将立即关联到User
记录。由于您正在尝试处理多个电子邮件问题,我建议将电子邮件地址分解为单独的模型:
class EmailAddress << ActiveRecord::Base
# == DB Columns
# id :integer
# user_id :integer
# email :string
belongs_to :user
has_many :suggestions
validates :email, presence :true
end
相应地更改其他模型:
class Suggestion << ActiveRecord::Base
...
belongs_to :email
end
class User << ActiveRecord::Base
...
has_many :email
end
您可以选择立即创建User
或将其推迟到实际注册帐户(我会推迟)。
至于某人在未注册时创建建议并且必须在事后进行该关联的情况。这个结构使这更容易,但我实际上不允许这个。我会告诉用户类似this email address is already registered, please sign in to submit your suggestion
的内容。假设你想确保人们不会错误地以其他人的名义创建建议。