Skip to content

统计数据分组

创建路由

打开routes.rb修改内容,修改后可以在终端执行bin/rails routes命令,进行查看。使用了collection,可以在items后面添加参数来组成路由。

ruby
Rails.application.routes.draw do
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  # root "articles#index"
  get '/' ,to: 'home#index'
  
  namespace :api do
    namespace :v1 do
      resources :validation_codes, only: [:create]
      resource :session, only: [:create, :destory]
      resource :me, only: [:show]
      resources :items do
        collection do
          get :summary
        end
      end
      resources :tags
    end
  end
end

按时间分组

get /api/v1/items/summary


  1. 写测试用例
ruby
require 'rails_helper'

RSpec.describe "Items", type: :request do
   describe "统计数据" do
    it '按天分组' do
      user = User.create! email: '1@qq.com'
      tag = Tag.create name: 'tag', sign: 'x', user_id:
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-20T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-20T00:00:00+08:00', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-19T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-19T00:00:00+08:00', user_id: user.id
      get '/api/v1/items/summary', params: {
        happened_after: '2018-01-01',
        happened_before: '2019-01-01',
        kind: 'expenses',
        group_by: 'happen_at'
      }, headers: user.generate_auth_header
      expect(response).to have_http_status 200
      json = JSON.parse response.body
      expect(json['groups'].size).to eq 3
      expect(json['groups'][0]['happen_at']).to eq '2018-06-18'
      expect(json['groups'][0]['amount']).to eq 300
      expect(json['groups'][1]['happen_at']).to eq '2018-06-19'
      expect(json['groups'][1]['amount']).to eq 300
      expect(json['groups'][2]['happen_at']).to eq '2018-06-20'
      expect(json['groups'][2]['amount']).to eq 300
      expect(json['total']).to eq 900
    end
  end
end
  1. 写代码

创建了一个hash表,用于处理数据。获取到时间后由于有时区的问题,要指定时区,于是使用in_time_zone(..)然后在进行格式化。但是指定时区还是有问题的,若是用户去了其他时区就会发现bug。其中%y-%m-%d来表示时间,也可以用ruby的简单写法%F

<=>可以理解为比较,sort的返回值也是三个,和JavaScript的类似,具体详细内容可以查看链接

处理好hash表后在进行mapsort处理得到根据happen_at的字段排好序的groups。

ruby
class Api::V1::ItemsController < ApplicationController
    def summary
      hash = Hash.new
      items = Items
        .where(user_id: request.env['current_user_id'])
        .where(kind: params[:kind])
        .where(happen_at: params[:happen_after]..params[:happen_before])
      items.each do |item|
        #获取到时间后由于有时区的问题,要指定时区,然后格式化。
        key = item.happen_at.in_time_zone('Beijing').strftime('%F')
        # hash[key] = hash[key] || 0 ruby简写如下
        hash[key] ||= 0
        hash[key] += item.amount
      end
      groups = hash
        .map { |key, value| { "happen_at": key, amount: value } }
        .sort { |a, b| a[:happen_at] <=> b[:happen_at] }
      render json: {
        groups: groups,
        total: items.sum(:amount)
      }
    end
end

按tag_id分组

接口还是同一个。

  1. 写测试用例
ruby
require 'rails_helper'

RSpec.describe "Items", type: :request do
  describe "统计数据" do
    it '按标签ID分组' do
      user = User.create! email: '1@qq.com'
      tag1 = Tag.create! name: 'tag1', sign: 'x', user_id: user.id
      tag2 = Tag.create! name: 'tag2', sign: 'x', user_id: user.id
      tag3 = Tag.create! name: 'tag3', sign: 'x', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag1.id, tag2.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag2.id, tag3.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 300, kind: 'expenses', tags_id: [tag3.id, tag1.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      get '/api/v1/items/summary', params: {
        happened_after: '2018-01-01',
        happened_before: '2019-01-01',
        kind: 'expenses',
        group_by: 'tag_id'
      }, headers: user.generate_auth_header
      expect(response).to have_http_status 200
      json = JSON.parse response.body
      expect(json['groups'].size).to eq 3
      expect(json['groups'][0]['tag_id']).to eq tag3.id
      expect(json['groups'][0]['amount']).to eq 500
      expect(json['groups'][1]['tag_id']).to eq tag1.id
      expect(json['groups'][1]['amount']).to eq 400
      expect(json['groups'][2]['tag_id']).to eq tag2.id
      expect(json['groups'][2]['amount']).to eq 300
      expect(json['total']).to eq 600
    end
  end
end
  1. 写代码
ruby
class Api::V1::ItemsController < ApplicationController
    def summary
      hash = Hash.new
      items = Item
        .where(user_id: request.env['current_user_id'])
        .where(kind: params[:kind])
        .where(happen_at: params[:happened_after]..params[:happened_before])
      items.each do |item|
        if params[:group_by] == 'happen_at'
          key = item.happen_at.in_time_zone('Beijing').strftime('%F')
          hash[key] ||= 0
          hash[key] += item.amount
        else
          item.tags_id.each do |tag_id|
            key = tag_id
            hash[key] ||= 0
            hash[key] += item.amount
          end
        end
      end
      groups = hash
        .map { |key, value| {"#{params[:group_by]}": key, amount: value} }
      if params[:group_by] == 'happen_at'
        groups.sort! { |a, b| a[:happen_at] <=> b[:happen_at] }
      elsif params[:group_by] == 'tag_id'
        groups.sort! { |a, b| b[:amount] <=> a[:amount] }
      end
      render json: {
        groups: groups,
        total: items.sum(:amount)
      }
    end
end

更新API文档

ruby
require 'rails_helper'
require 'rspec_api_documentation/dsl'

resource "账目" do
  let(:current_user) { User.create email: '1@qq.com' }
  let(:auth) { "Bearer #{current_user.generate_jwt}" }
  get "/api/v1/items/summary" do
    authentication :basic, :auth
    parameter :happened_after, '时间起点', required: true
    parameter :happened_before, '时间终点', required: true
    parameter :kind, '账目类型', enum: ['expenses', 'income'], required: true
    parameter :group_by, '分组依据', enum: ['happen_at', 'tag_id'], required: true
    response_field :groups, '分组信息'
    response_field :total, "总金额(单位:分)"
    let(:happened_after) { '2018-01-01' }
    let(:happened_before) { '2019-01-01' }
    let(:kind) { 'expenses' }
    example "统计信息(按happen_at分组)" do
      user = current_user
      tag = Tag.create! name: 'tag1', sign: 'x', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-20T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-20T00:00:00+08:00', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-19T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag.id], happen_at: '2018-06-19T00:00:00+08:00', user_id: user.id
      do_request group_by: 'happen_at'
      expect(status).to eq 200
      json = JSON.parse response_body
      expect(json['groups'].size).to eq 3
      expect(json['groups'][0]['happen_at']).to eq '2018-06-18'
      expect(json['groups'][0]['amount']).to eq 300
      expect(json['groups'][1]['happen_at']).to eq '2018-06-19'
      expect(json['groups'][1]['amount']).to eq 300
      expect(json['groups'][2]['happen_at']).to eq '2018-06-20'
      expect(json['groups'][2]['amount']).to eq 300
      expect(json['total']).to eq 900
    end

    example "统计信息(按tag_id分组)" do
      user = current_user
      tag1 = Tag.create! name: 'tag1', sign: 'x', user_id: user.id
      tag2 = Tag.create! name: 'tag2', sign: 'x', user_id: user.id
      tag3 = Tag.create! name: 'tag3', sign: 'x', user_id: user.id
      Item.create! amount: 100, kind: 'expenses', tags_id: [tag1.id, tag2.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 200, kind: 'expenses', tags_id: [tag2.id, tag3.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      Item.create! amount: 300, kind: 'expenses', tags_id: [tag3.id, tag1.id], happen_at: '2018-06-18T00:00:00+08:00', user_id: user.id
      do_request group_by: 'tag_id'
      expect(status).to eq 200
      json = JSON.parse response_body
      expect(json['groups'].size).to eq 3
      expect(json['groups'][0]['tag_id']).to eq tag3.id
      expect(json['groups'][0]['amount']).to eq 500
      expect(json['groups'][1]['tag_id']).to eq tag1.id
      expect(json['groups'][1]['amount']).to eq 400
      expect(json['groups'][2]['tag_id']).to eq tag2.id
      expect(json['groups'][2]['amount']).to eq 300
      expect(json['total']).to eq 600
    end
  end
end

然后重新执行bin/rails rake docs:generate,然后执行http-server doc/api进行查看。