在db fetch之后对activerecord进行子类化并维护子类

She*_*hea 3 ruby activerecord ruby-on-rails sti rails-models

我有一个ActiveRecord模型Media这应该能够存储有关不同类型的媒体(类似结构化信息Media::Book,Media::Movie,Media::Music).但是,每个子类都有独特的方法.

# TABLE medias
# string :title
# string :description
# integer :media_type

class Media < ActiveRecord::Base
end

class Media
  class Book < Media
    def reviews
      GoogleBooks.search(name).get_reviews
    end
  end
  class Movie < Media
    def reviews
      IMDB.search_movies(name).reviews
    end
  end
  class Music < Media
    def reviews
      Lastfm.search(name).comments
    end

    def music_video
      Youtube.search(name).first.embed_html
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

如果我使用Media::Book.new("Harry Potter").reviews,这将有效,但我希望能够使用

Media.find("Harry Potter")
=> Media::Book
Run Code Online (Sandbox Code Playgroud)

Media.find("Harry Potter").reviews
Run Code Online (Sandbox Code Playgroud)

我知道我应该使用media_type来实现这一点,但我不知道,如果那里有一个更好的方式来做到这一点不是覆盖每一个ActiveRecord的数据库接口方法(User.medias,find,find_by_etc,where,order,limit,all)和更换他们的每一个返回值.

pau*_*kul 7

您可以使用ActiveRecords单表继承功能.它使用模型表上的另一列(默认为名为"type"的列)来确定每条记录的模型类型.

只需将一个字符串类型列添加到medias表中,当Rails在数据库模式中找到该列时,它将为您提供魔力.如果AR可以将类型添加到media_type列中,则还可以使用set_inheritance_column类方法更改用于单表继承的列.

class Media < ActiveRecord::Base
  set_inheritance_column :media_type
end
Run Code Online (Sandbox Code Playgroud)

然后,您将在此列中找到具有完整命名空间类名的相应对象的类名.(例如:"Media :: Book")也就是说,您不想手动更改类型列(或您使用的任何列)的内容.ActiveRecord将自己处理它.

查看http://api.rubyonrails.org/classes/ActiveRecord/Base.html并在该页面中搜索"单表继承"以获取更多信息

编辑:刚刚意识到你的media_type列是一个整数.因此将它用于STI是行不通的.只需坚持使用字符串类型列,让AR为您完成剩下的工作.