rails 4在多表继承模型上的accepts_nested_attributes_for

时间:2013-09-22 02:30:34

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

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

以下是一切如何运作:

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

模型/ announcement.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 action很简单 - 它只是从params发出一个新的公告,并试图保存它。

此设置没有错误,一切似乎都能正常运行。

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

这是有道理的,因为acts_as_topic实际上只是在Announcement模型和Topic模型之间创建了一个has_one关系,而Discussable模块就像公告is_a Topic一样伪造它,即使它确实不是。

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

0 个答案:

没有答案