Подтвердить что ты не робот

Rails: переопределение as_json для динамического значения - есть ли более разумный способ?

Я хочу вывести список партнерских ссылок, каждый из которых помечен для идентификации текущего пользователя. Это было бы просто в HTML, но мы пишем API, поэтому вывод - JSON.

У меня есть работа, но это кажется слишком сложным. Это лучший подход?

Моя модель, AffiliateLink содержит поле (необработанный HTML-код), который я буду преобразовывать и выводить на лету, добавляя токен. У меня есть модельный метод, который производит замену - это нетривиально, потому что мы используем несколько веток, и у каждого есть специальное правило преобразования, которое этот метод знает о:

def link_with_token(user_token)
  # some gnarly code that depends on a lot of stuff the model knows
  # that returns a proper link
end

Чтобы получить правильную ссылку html в JSON, я сделал следующее:

  • добавить attr_accessor :link_html в модель
  • добавить метод экземпляра для установки нового аксессора

...

def set_link_html(token)
  self.link_html = link_with_tracking_token(token)
end
  • переопределить as_json в модели, заменив исходный html_code на link_html

...

def as_json(options = {})
  super(:methods => :link_html, :except => :html_code)
end
  • итерация по коллекции, возвращаемой в методе контроллера, для преобразования

...

def index
  @links = Admin::AffiliateLink.all  # TODO, pagination, etc.

  respond_to do |format|
    format.html # index.html.erb
    format.json do
      @links.each do |link|
        link.set_link_html(account_tracking_token)
      end
      render json: @links
    end
  end
end

Это похоже на то, что нужно сделать только для того, чтобы сделать мою трансформацию с учетом напряженности. Полезные предложения (связанные с этой проблемой, а не с другими аспектами кода, который сейчас находится в движении) приветствуются.

4b9b3361

Ответ 1

1) Быстрое решение вашей проблемы (как показано здесь):

affiliate_links_controller.rb

def index
  @links = Admin::AffiliateLink.all  # TODO, pagination, etc.

  respond_to do |format|
    format.html # index.html.erb
    format.json do
      render json: @links.to_json(:account_tracking_token => account_tracking_token)
    end
  end
end

AffiliateLink.rb

# I advocate reverse_merge so passed-in options overwrite defaults when option
# keys match.
def as_json(options = {})
  json = super(options.reverse_merge(:except => :html_code))
  json[:link_with_token] = link_with_token(options[:account_tracking_token])
  json
end

2) Более хардкорное решение, если вы действительно пишете API:


3) И, наконец, удобное решение. Если у вас есть удобное отношение модели, это чисто:

Притворство AffiliateLink belongs_to :user. И предполагая, что user_token является доступным атрибутом пользователя.

AffiliateLink.rb

# have access to user.user_token via relation
def link_with_token
  # some gnarly code that depends on a lot of stuff the model knows
  # that returns a proper link
end

def as_json(options = {})
  super(options.reverse_merge(:methods => :link_with_token, :except => :html_code))
end

affiliate_links_controller.rb

def index
  @links = Admin::AffiliateLink.all  # TODO, pagination, etc.

  respond_to do |format|
    format.html # index.html.erb
    format.json do
      render json: @links
    end
  end
end