【问题标题】:How to have a has_one with an alias in Rails 4+如何在 Rails 4+ 中拥有一个带别名的 has_one
【发布时间】:2016-01-14 07:05:08
【问题描述】:

我有当前的模型结构

publisher
---------
has_many :digest_templates
has_one :active_template

digest_templates
---------
belongs_to :publisher, optional: true

数据库结构为:

publishers
---------
t.string :name
t.string :permalink
t.string :api_key
t.string :domain
t.reference :digest_template, index: true, foreign_key: true

digest_templates
---------
t.text :html
t.text :text
t.references :publisher, index: true, foreign_key: true
t.boolean :global, default: false # this is for internally developed templates

在任何给定时间,发布者都可以拥有一个活动模板,但可以为自己创建任意数量的自定义模板。我想这样做,以便可以进行以下调用:

Publisher.templatesPublisher.active_template

主要问题是我在同一个表中有全局模板和用户创建的模板。是否有可能使它与这种架构一起工作?还是有更好的做事方式?

【问题讨论】:

  • 一个活动模板同时也是一个摘要模板?如果是这样,您将在数据库中保存两次相同的数据。
  • @ArslanAli active_template 只是对处于活动状态的 digest_template 的 ID 引用。
  • 这似乎可行。您遇到什么问题? publisher.templates 应该返回什么?它是否应该简单地从has_many 关系中返回所有关联digest_templates
  • 你是如何指定活动模板的?

标签: ruby-on-rails ruby-on-rails-4 activerecord activemodel


【解决方案1】:

几个问题:

  1. publishers 表中不需要t.references :digest_template(如果是has_many,则所有外键都在关联表中,即you've got already

  2. 您尚未在数据库中定义模板是否“活动”


我看到的最大问题是无法定义模板是否“活跃”。我会在您的 publishers 表中添加一个名为 active 的 bool 列:

# db/migrate/add_active_to_templates______.rb
class DigestTemplate < ActiveRecord::Migration
    change_table :templates do |t|
       t.boolean :active, default: :false
    end
end

您拥有的模式是 template belongs_to publisher,它为您提供了一个工作范围。那么问题就变成了如何定义哪些模板是“活动的”。

我会使用的解决方案如下:

#app/models/digest_template.rb
class DigestTemplate < ActiveRecord::Base
   belongs_to :publisher
   validates :active, uniqueness: { scope: :user_id }
   scope :active, -> { where active: true }
end

这将允许您调用:

#app/models/publisher.rb
class Publisher < ActiveRecord::Base
   has_many :digest_templates

   def active_template
      digest_templates.find_by active: true 
   end
end

--

您的问题有点错误,因为您无法调用Publisher.active_template,因为这是一个class 方法。

您必须执行以下操作:

@publisher = Publisher.find params[:id]
@publisher.digest_templates #-> returns all (including active)
@publisher.active_template  #-> returns only active

【讨论】:

  • 就像 Arslan 的情况一样,除了存在全局可访问的模板(global 设置为 true)这一事实之外,这几乎是正确的。这些是所有用户都可以访问的默认模板。因此,在这种情况下,简单地将 active 设置为 true 是行不通的。
【解决方案2】:

对于最简单的情况,我会说在digest_templates 中添加boolean 类型的列active,并添加如下验证:

validate_uniqueness_of :active, if: :active_template?

使用这行代码,您一次只能拥有一个active 等于true 的模板。它将为您节省一张桌子。

现在,您只需要定义一个像has_many :templates 这样的关系,并且您可以定义实例方法来获取活动模板。

【讨论】:

  • 当发布者将默认模板设置为全局时,这不起作用。他们不拥有该模板,因此无法判断。
  • 因此模板以两种方式属于用户:1)用户可以是该模板的所有者; 2) 用户可以将该模板作为他的默认模板。对吗?
  • 是的。但是还有另外一件事:当第一次生成用户时,他们被分配了一个默认模板,称为 global(换句话说,所有用户都可以访问它)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-28
  • 1970-01-01
  • 1970-01-01
  • 2011-01-29
  • 1970-01-01
  • 2016-01-17
  • 2023-03-24
相关资源
最近更新 更多