在Rails中的STI下动态创建自定义getter和setter

时间:2016-07-02 09:30:00

标签: ruby-on-rails ruby metaprogramming

我对元编程比较陌生,我试图在单个表继承下定义子模型中的getter和setter,如下所示:

# app/models/player.rb
class Player < ActiveRecord::Base
  serialize :equipments

  protected
  # Define getters for setters for individual sports
  def attr_equipments(*attributes)
    attributes.each do |attribute|
      define_singleton_method(attribute) do
        self.equipments[attribute.to_sym]
      end

      define_singleton_method("#{attribute}=") do |value|
        self.equipments[attribute.to_sym] = value
      end
    end
  end
end

# app/models/baseball_player.rb
class BaseballPlayer < Player
  after_initialize do
    attr_equipments :bat, :glove
  end
end

在更高层,我想做这样的事情:

# app/controllers/baseball_players_controller.rb
class BaseballPlayersController < ApplicationController
  def new
    @baseball_player = BaseballPlayer
  end
end

# app/views/baseball_players/new.html.haml
=form_for(@baseball_player) do |f|
  =f.text_field :bat
  =f.text_field :glove
  =f.submit 

但是通过上面的示例,即使从控制台也无法获取或设置属性。

> p = BaseballPlayer.new
> p.bat
> # returns NoMethodError: undefined method `[]' for nil:NilClass

> p = BaseballPlayer.new
> p.bat = "Awesome bat"
> # returns ArgumentError: wrong number of arguments (0 for 2..3)

有人能帮我找到合适的方向吗?非常感谢提前。

1 个答案:

答案 0 :(得分:0)

我自己刚刚解决了这个问题..

对于将来的引用,此部分需要存储,因为序列化不会自动定义任何访问器。

# app/models/player.rb
class Player < ActiveRecord::Base
  # serialize :equipments -> does not create a setter or getter needed
  store :equipments

我在控制器中的create方法中也遇到错误:

def create
  @alarm = BaseballPlayer.new(alarm_params)
  # Error: undefined attribute 'bat'

解决了:

def create
  @alarm = BaseballPlayer.new
  @alarm.assign_attributes(alarm_params)