在Ruby on Rails中覆盖模型的“全部”方法

时间:2018-11-09 02:43:59

标签: ruby-on-rails

我有一个具有列的Account模型:

id :bigint(8)
name :string

app/models/account.rb中,我有:

class Account < ApplicationRecord
  has_one_attached :logo
end

这是一个API,控制器仅返回JSON。在我的控制器中,我有:

render :json => Account.all

上面的代码返回:

[
  {
    "id": 1,
    "name": "Example1"
  },
  {
    "id": 2,
    "name": "Example2"
  }
]

我还希望包含附加到返回的JSON的ActiveStorage文件的网址。

为了实现这一点,我正在控制器中执行此操作:

def index
  @accounts =  
    Account.all.map do |account|
      account =
        account.attributes.merge(
          :logo_url =>
            account.logo.attached? ?
              polymorphic_url(account.logo) : nil
        )
  end

  render :json => @accounts
end

这将返回:

[
  {
    "id": 1,
    "name": "Example1",
    "logo_url": "/path/to/logo.jpg"
  },
  {
    "id": 2,
    "name": "Example2",
    "logo_url": "/path/to/logo.jpg"
  }
]

但是,我不想在每次致电Account.all时执行此操作;我想在每次调用logo_url时自动添加Account.all

我想出了这个解决方案;而不是在控制器中调用它,我决定重写模型中的方法。在app/models/account.rb中,我添加了:

def self.all
  super.map do |account|
    account =
      account.attributes.merge(
        :logo_url =>
          account.logo.attached? ?
            polymorphic_url(account.logo) : nil
      )
  end
end

上面的代码效果很好。问题是方法findfind_bywhere和其他方法停止工作。而且,如果我从self.all中删除了account.rb方法,它将再次起作用。

以下代码:

Account.find_by :id => params[:id]
Account.find params[:id]

引发错误:

undefined method `where' for #<Array:0x00007fd09b68d670>

我相信这是因为self.all返回一个数组而不是活动记录。

如何覆盖模型中的all方法?

1 个答案:

答案 0 :(得分:1)

我认为您不想覆盖Account.all。 相反,您想更改模型的默认序列化。 试试这个:

class Account < ApplicationRecord

  has_one_attached :logo

  private

  def serializable_hash(options)
    super(options).merge("logo_url" => logo_url)
  end

  def logo_url
    logo.attached? ? polymorphic_url(account.logo) : nil
  end
end

控制器最终在模型上调用to_json,而最终将使用#serializable_hash。由于to_son使用选项来设置json的根,因此最好覆盖serializable_hash。另一种方法是为每个模型创建一个单独的序列化器类,但这应适合于简单的情况。