1

我有一个 rails 4 项目,我正在使用 MTI。这是一个论坛应用程序,除了几个从主题继承的模型(如公告和私人消息)外,我还有一个核心主题模型。

以下是它的工作原理:

models/topic.rb - 这是基本模型

class Topic < ActiveRecord::Base
  acts_as_taggable

  default_scope order('created_at DESC')

  #string title

  belongs_to :discussable, polymorphic: true, dependent: :destroy

  belongs_to :author, class_name: User
  has_many :posts, inverse_of: :topic, order: :created_at
  has_many :viewings
  has_many :viewers, class_name: User, through: :viewings, uniq: true
  has_many :watchings
  has_many :watchers, class_name: User, through: :watchings, uniq: true

  accepts_nested_attributes_for :posts, allow_destroy: true

  validates :title, presence: true
  validates :author_id, presence: true

  def base
    self
  end

end

模型/公告.rb

# this is a "child" class -- acts_as_topic sets that up, see next snippet
class Announcement < ActiveRecord::Base
  acts_as_topic

  default_scope includes(:topic).order('topics.created_at DESC')

  #datetime :displays_at
  validates :expires_at, timeliness: { after: lambda { self.displays_at }, allow_nil: true }

end

配置/初始化程序/discussable.rb

module Discussable
  def self.included(base)
    base.has_one :topic, as: :discussable, autosave: true
    base.validate :topic_must_be_valid
    base.alias_method_chain :topic, :autobuild
  end

  def topic_with_autobuild
    topic_without_autobuild || build_topic
  end

  def method_missing(meth, *args, &blk)
    topic.send(meth, *args, &blk)
  rescue NoMethodError
    super
  end

  protected
  def topic_must_be_valid
    unless topic.valid?
      topic.errors.each do |attr, message|
        errors.add(attr, message)
      end
    end
  end
end

class ActiveRecord::Base
  def self.acts_as_topic
    include Discussable
  end
end

和迁移:

class CreateTopics < ActiveRecord::Migration
  def change
    create_table :topics do |t|
      t.string :title, null: false
      t.references :author, null: false

      t.references :discussable
      t.string :discussable_type

      t.integer :posts_count, null: false, default: 0

      t.timestamps
    end
  end
end

class CreateAnnouncements < ActiveRecord::Migration
  def change
    create_table :announcements do |t|
      t.datetime :displays_at
      t.datetime :expires_at
    end
  end
end

意见/公告/new.html.erb

<%= form_for @announcement do |f| %>
    <%= f.text_field :title, placeholder: 'Title' %><br />
    <%= f.fields_for :posts do |post_f| %>
        <%= post_f.text_area :content %>
        <%= post_f.hidden_field :author_id, value: current_user.id %><br />
    <% end %>
    <%= f.text_field :tag_list, placeholder: 'Tags' %><br />
    <%= f.text_field :displays_at, placeholder: 'Display At' %><br />
    <%= f.text_field :expires_at, placeholder: 'Expire At' %><br />
    <%= f.hidden_field :author_id %><br />
    <%= f.submit %>
<% end %>

公告#create 操作是微不足道的——它只是从参数中创建一个新的公告,并尝试保存它。

此设置没有错误,一切似乎都运行良好。

问题是announcements#create 创建了公告并完全忽略了帖子的嵌套属性。

这是有道理的,因为acts_as_topic实际上只是在 Announcement 模型和 Topic 模型之间创建了一个 has_one 关系,而 Discussable 模块将其伪装成公告 is_a Topic 一样,尽管实际上并非如此。

所以我的问题是:我怎样才能伪造它,以便 Announcement 模型的 ActiveRecord 初始化程序的内部接受帖子的嵌套属性,这实际上是与 Topic 模型的关联?

4

0 回答 0