我有一个 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 模型的关联?