【问题标题】:How to make database entries stick to a User's account if those entries were created before the User account was如果这些条目是在用户帐户创建之前创建的,如何使数据库条目粘在用户帐户上
【发布时间】:2013-05-11 23:53:25
【问题描述】:

我正在尝试考虑一种最佳方式,即允许用户在不创建帐户的情况下创建数据库对象,然后在他们决定注册时将这些对象与用户的帐户相关联。我将描述一个示例应用程序,我希望它如何运行,以及我想出的方法。我正在寻找对我的方法的批评/改进,或者是你们中的一个人,我的程序员伙伴们想要的更好的方法。

示例应用程序

假设我们有一个名为 Suggestion Box 的 Rails 应用程序。此应用程序允许用户访问该站点并输入建议。 Suggestion 需要描述和电子邮件地址。用户无需登录。以下是模型:

app/models/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

app/models/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" >]

如果我们询问 Frank 的建议,我们会得到全部 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!">]

现在我们如何使弗兰克和他过去的建议之间的这种联系自动化?

方法

#1 Cookies

当未登录的用户提交会话时,我可以在 cookie 中存储有关创建的建议的指示符。然后,当他们注册时,我可以使用此信息来查找建议并将其分配给用户。

我不太喜欢这种方法,因为当用户访问多个设备时它会崩溃。

#2 创建回调后

当用户注册时,我可以运行如下所示的创建后回调:

app/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 类上编写一个回调来检查匹配的电子邮件。

app/models/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? (好或坏)除此之外,我是否可以使用另一个技巧将弗兰克与他通过其他电子邮件地址提出的建议联系起来?你能想出比我更好的方法吗?

感谢您的建议!

【问题讨论】:

    标签: ruby-on-rails database callback user-accounts


    【解决方案1】:

    您似乎试图同时解决两种情况:分配用户是您的主要问题,以及为一个帐户处理多个电子邮件地址。

    email address 字段在两个模型中重复。最初我会建议将电子邮件地址保留在User,并创建匿名(无名称)Users,然后从那里构建。这将改变您的 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。假设您想确保人们不会以其他人的名义错误地提出建议。

    【讨论】:

    • 感谢您的回答。我喜欢您将电子邮件放入单独模型的想法。然后User 对象可以通过Email 对象拥有Suggestion 对象。为了防止人们在另一封电子邮件中错误地输入建议,我打算通过向提交者发送电子邮件来确认建议,除非他们已登录。
    • 很高兴您喜欢这个建议。对于每个未注册的建议,我肯定会发送一封确认电子邮件。但是,一旦用户拥有帐户,要求登录而不是继续发送确认电子邮件会更容易/更统一。如果您觉得该解决方案有用,请记得接受该解决方案。
    猜你喜欢
    • 1970-01-01
    • 2020-03-25
    • 1970-01-01
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多