4

我尝试在表单中设置单表继承模型类型。所以我有一个属性选择菜单:类型,值是 STI 子类的名称。问题是错误日志不断打印:

警告:无法批量分配这些受保护的属性:类型

所以我在模型中添加了“attr_accessible:type”:

class ContentItem < ActiveRecord::Base
  # needed so we can set/update :type in mass
  attr_accessible :position, :description, :type, :url, :youtube_id, :start_time, :end_time
  validates_presence_of :position
  belongs_to :chapter
  has_many :user_content_items
end

不会改变任何东西,在控制器中调用 .update_attributes() 之后 ContentItem 仍然有 :type=nil 。知道如何从表单中批量更新 :type 吗?

4

5 回答 5

20

我们可以覆盖 attributes_protected_by_default

class Example < ActiveRecord::Base

  def self.attributes_protected_by_default
    # default is ["id","type"]
    ["id"]
  end
end

e = Example.new(:type=>"my_type")
于 2010-11-17T03:30:38.330 回答
9

您应该根据要创建的子类使用正确的构造函数,而不是调用超类构造函数并手动分配类型。让 ActiveRecord 为您执行此操作:

# in controller
def create
   # assuming your select has a name of 'content_item_type'
   params[:content_item_type].constantize.new(params[:content_item])
end

这为您提供了在子类中定义不同行为的好处 initialize() 方法或回调。如果您不需要这些好处或计划频繁更改对象的类,您可能需要重新考虑使用继承并坚持使用属性。

于 2009-10-21T18:22:20.660 回答
6

railsforum.com 上的 Duplex 找到了一种解决方法:

在表单和模型中使用虚拟属性,而不是直接输入:

def type_helper   
  self.type 
end 
def type_helper=(type)   
  self.type = type
end

像魅力一样工作。

于 2009-10-21T18:17:45.807 回答
4

“类型”有时会引起麻烦......我通常使用“种类”来代替。

另见: http ://wiki.rubyonrails.org/rails/pages/ReservedWords

于 2009-10-21T16:20:58.160 回答
1

我跟着http://coderrr.wordpress.com/2008/04/22/building-the-right-class-with-sti-in-rails/解决了我遇到的同样问题。我对 Rails 世界还很陌生,所以不太确定这种方法是好是坏,但效果很好。我已经复制了下面的代码。

class GenericClass < ActiveRecord::Base
  class << self
    def new_with_cast(*a, &b)
      if (h = a.first).is_a? Hash and (type = h[:type] || h['type']) and (klass = type.constantize) != self
      raise "wtF hax!!"  unless klass < self  # klass should be a descendant of us
      return klass.new(*a, &b)
    end
    new_without_cast(*a, &b)
  end
  alias_method_chain :new, :cast
end

class X < GenericClass; end
GenericClass.new(:type => 'X') # => #<X:0xb79e89d4 @attrs={:type=>"X"}>
于 2010-08-20T05:40:13.457 回答