Переопределить метод «все» модели в Ruby on Rails - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть модель 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"
  }
]

Я также хочу включить URL-адрес файла ActiveStorage, прикрепленного к возвращенному JSON.

Чтобы достичь этого, я делаю это в контроллере:

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 в модели?

1 Ответ

0 голосов
/ 09 ноября 2018

Не думаю, что вы хотите переопределить 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. Другой подход заключается в создании отдельных классов сериализатора для каждой модели, но это должно подходить для простого случая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...