我有一个具有列的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
上面的代码效果很好。问题是方法find
,find_by
,where
和其他方法停止工作。而且,如果我从self.all
中删除了account.rb
方法,它将再次起作用。
以下代码:
Account.find_by :id => params[:id]
Account.find params[:id]
引发错误:
undefined method `where' for #<Array:0x00007fd09b68d670>
我相信这是因为self.all
返回一个数组而不是活动记录。
如何覆盖模型中的all
方法?
答案 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
。另一种方法是为每个模型创建一个单独的序列化器类,但这应适合于简单的情况。