Rails에서 API 응답을 모델로 변환

3944 단어 railsruby
바로 본론으로 들어가겠습니다.

Stripe에서 사용자에게 청구서를 보여주는 예를 들어보겠습니다.

먼저 구현에 대한 걱정 없이 갖고 싶은 것을 작성해 봅시다.

나는 짧고 깔끔한 컨트롤러를 좋아한다. 다음과 같은 작업이 수행됩니다.
app/controllers/invoices_controller.rb
class InvoicesController < ApplicationController
  def index
    @invoices = Invoice.find_all_by_user(current_user)
  end

  def show
    @invoice = Invoice.new(params[:id])
    render
  end
end


다음은 내가 보기에 원하는 것입니다. app/views/invoices/_invoice.html.erb
<% unless (invoice.total == 0) %>
  <tr>
    <td><%= link_to invoice.number, invoice_path(invoice.id) %></td>
    <td><%= invoice.date %></td>
    <td><%= number_to_currency(invoice.total, negative_format: "(%u%n)") %></td>
    <td><%= invoice.period_start %> to <%= invoice.period_end %></td>
    <td><%= invoice.paid? ? 'Paid' : 'Unpaid' %></td>
  </tr>
<% end %>


위에서 했던 것처럼 인터페이스를 먼저 작성하는 것이 구현하는 동안 많은 명확성을 제공한다는 것을 경험했습니다. 이제 모델에서 구현해 보겠습니다.
app/models/invoice.rb
class Invoice

  attr_reader :stripe_invoice

  def self.find_all_by_user(user)
    if user.present?
      stripe_invoices_for_user(user).map do |invoice|
        new(invoice)
      end
    else
      []
    end
  end

  def initialize(invoice_id_or_object)
    if invoice_id_or_object.is_a? String
      @stripe_invoice = retrieve(invoice_id_or_object)
    else
      @stripe_invoice = invoice_id_or_object
    end
  end

  def to_partial_path
    "invoices/#{self.class.name.underscore}"
  end

  def id
    stripe_invoice.id
  end

  def number
    stripe_invoice.number
  end

  def total
    cents_to_dollars(stripe_invoice.total)
  end

  def date
    convert_stripe_time(stripe_invoice.date)
  end

  def paid?
    stripe_invoice.paid
  end

  def subscription
    stripe_invoice.subscription
  end

  def period_start
    convert_stripe_time(stripe_invoice.period_start)
  end

  def period_end
    convert_stripe_time(stripe_invoice.period_end)
  end

  def user
    @user ||= User.find_by(stripe_customer_id: stripe_invoice.customer)
  end

  def balance
    if paid?
      0.00
    else
      amount_due
    end
  end

  def amount_due
    cents_to_dollars(stripe_invoice.amount_due)
  end

  def subtotal
    cents_to_dollars(stripe_invoice.subtotal)
  end

  def amount_paid
    if paid?
      amount_due
    else
      0.00
    end
  end

  def plan
    stripe_invoice.lines.data[0].plan.name
  end

  def plan_amount
    cents_to_dollars stripe_invoice.lines.data[0].plan.amount
  end

  def pay
    stripe_invoice.pay
  end

  def self.pay_if_pending(user)
    invoices = find_all_by_user(user)
    unless invoices.empty? || invoices.first.paid?
      invoices.first.pay
    end
  end

  def self.upcoming(user)
    new(Stripe::Invoice.upcoming(customer: user.stripe_customer_id) || nil )
  end

  private

  def self.stripe_invoices_for_user(user)
    Stripe::Invoice.all(customer: user.stripe_customer_id).data
  end

  def retrieve(invoice_id)
    Stripe::Invoice.retrieve(invoice_id)
  end

  def convert_stripe_time(time)
    Time.zone.at(time).strftime('%D')
  end

  def cents_to_dollars(amount)
    amount / 100.0
  end
end


여기에서 Stripe gem은 응답에 대한 많은 메소드를 노출합니다. 그러나 바닐라 JSON 응답은 모두 동일하게 수행할 수 있습니다.

몇 년 전에 이 패턴 형식Upcase을 배웠습니다. 그 이후로 나는 항상 이와 같은 API 응답을 파싱하고 있습니다. Upcase는 지금 무료이며 확실히 볼 가치가 있습니다.

코드를 gist 으로 다운로드하십시오.

좋은 웹페이지 즐겨찾기