• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hathitrust / otis / 13816285298

12 Mar 2025 04:16PM UTC coverage: 97.466% (-0.2%) from 97.646%
13816285298

Pull #247

github

web-flow
Merge a8436da05 into ed9cf628f
Pull Request #247: Rails 8 js

28 of 28 new or added lines in 16 files covered. (100.0%)

6 existing lines in 2 files now uncovered.

3192 of 3275 relevant lines covered (97.47%)

102.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.74
/app/controllers/ht_ssd_proxy_reports_controller.rb
1
# frozen_string_literal: true
2

3
class HTSSDProxyReportsController < ApplicationController
2✔
4
  # This class is only responsible for an index page. There are no detail views or editing
5
  # capabilities.
6
  # Bootstrap Table gets all its data server-side, so most of the plumbing in this class
7
  # is in support of `format=json` queries.
8

9
  # Extensive use is made of Ransack (https://github.com/activerecord-hackery/ransack)
10
  # which I chose because assembling LIKE queries in this controller appeared likely to
11
  # become a rabbit hole.
12

13
  # Pagination is provided by Kaminari. See the `results.page(...).per(...)` calls.
14

15
  # This is what a JSON request looks like when it comes in from Bootstrap Table:
16
  # ?format=json&pageSize=10&pageNumber=1&filter={"rights_code":"pdus"}&dateStart=2023-09-19&dateEnd=2024-09-19&sortName=inst_code&sortOrder=asc
17
  # - dateStart and dateEnd are the two date ranges initially populated by @date_start and @date_end
18
  # - sortName and sortOrder, if present, reflect the user's interaction with the column sort controls.
19
  # - filter={...} reflects the filters selected or typed into the column filters in the table.
20

21
  # The `filter` keys come from HTSSDProxyReportPresenter::ALL_FIELDS which combines relevant
22
  # columns from the three associated database tables.
23

24
  # Used by `#matchers` to translate `filter` keys into values that the `#ransack` method
25
  # can apply to the Active Record query. Many of these (the text input ones)
26
  # are of the form `*_i_cont` which is a case-insensitive contains equivalent to "LIKE '%value%'".
27
  # Those selectable by a dropdown menu can use an equality (`_eq`)  matcher.
28
  RANSACK_MATCHERS = {
2✔
29
    "author" => :ht_hathifile_author_i_cont,
30
    "bib_num" => :ht_hathifile_bib_num_cont,
31
    "content_provider_code" => :ht_hathifile_content_provider_code_eq,
32
    "datetime" => :datetime_start,
33
    "digitization_agent_code" => :ht_hathifile_digitization_agent_code,
34
    "email" => :email_i_cont,
35
    "htid" => :htid_i_cont,
36
    "imprint" => :ht_hathifile_imprint_i_cont,
37
    "inst_code" => :inst_code_eq,
38
    "institution_name" => :ht_institution_name_i_cont,
39
    "rights_code" => :ht_hathifile_rights_code_eq,
40
    "rights_date_used" => :ht_hathifile_rights_date_used_eq,
41
    "title" => :ht_hathifile_title_i_cont
42
  }
43

44
  # Translation table from params[:sortName] to a form Ransack can understand.
45
  RANSACK_ORDER = {
2✔
46
    "author" => :ht_hathifile_author,
47
    "bib_num" => :ht_hathifile_bib_num,
48
    "content_provider_code" => :ht_hathifile_content_provider_code,
49
    "datetime" => :datetime,
50
    "digitization_agent_code" => :ht_hathifile_digitization_agent_code,
51
    "email" => :email,
52
    "htid" => :htid,
53
    "imprint" => :ht_hathifile_imprint,
54
    "inst_code" => :inst_code,
55
    "institution_name" => :ht_institution_name,
56
    "rights_code" => :ht_hathifile_rights_code,
57
    "rights_date_used" => :ht_hathifile_rights_date_used,
58
    "title" => :ht_hathifile_title
59
  }
60

61
  def index
2✔
62
    respond_to do |format|
3✔
63
      format.html do
3✔
64
        # Populate the date range fields with the latest datetime and
65
        # then the start date a year earlier
66
        @date_end = HTSSDProxyReport.maximum(:datetime).tap do |dt_end|
2✔
67
          @date_start = (dt_end - 1.year).to_date.to_s
2✔
68
        end.to_date.to_s
69
      end
70
      format.json do
3✔
71
        render json: json_query
1✔
72
      end
73
    end
74
  end
75

76
  private
2✔
77

78
  # @return [Hash] value to be returned to Bootstrap Table as JSON
79
  def json_query
2✔
80
    # Create a Ransack::Search with all of the filter fields translated into Ransack matchers.
81
    search = HTSSDProxyReport.includes(:ht_hathifile, :ht_institution)
1✔
82
      .ransack(matchers)
83
    # Apply the sort field and order, or default if not provided.
84
    # Ransack requires lower case sort direction.
85
    sort_name = RANSACK_ORDER.fetch(params[:sortName], "datetime")
1✔
86
    sort_order = params.fetch(:sortOrder, "asc")
1✔
87
    search.sorts = "#{sort_name} #{sort_order.downcase}"
1✔
88
    # Extract HTSSDProxyReport::ActiveRecord_Relation
89
    result = search.result
1✔
90
    # total is the number of results after user-selected filters e.g. {"rights_code":"pdus"}
91
    # totalNotFiltered (see a few lines below) is the SELECT * for the whole shebang
92
    total = result.count
1✔
93
    # Paginate using Kaminari. index UI is always paginated.
94
    # When exporting to Excel and the like, there is no pagination
95
    # (hence performance issues on large data sets).
96
    if params[:pageNumber] && params[:pageSize]
1✔
UNCOV
97
      result = result.page(params[:pageNumber]).per(params[:pageSize])
×
98
    end
99
    # Translate each row of the result into JSON and stick it into struct with totals.
100
    {
101
      total: total,
1✔
102
      totalNotFiltered: HTSSDProxyReport.count,
103
      rows: result.map { |line| line_to_json line }
10✔
104
    }
105
  end
106

107
  # Use presenter to translate HTSSDProxyReport into JSON hash.
108
  # This is called for each object in the result.
109
  def line_to_json(report)
2✔
110
    report = presenter report
10✔
111
    HTSSDProxyReportPresenter::ALL_FIELDS.to_h do |field|
10✔
112
      [field, report.field_value(field)]
130✔
113
    end
114
  end
115

116
  def presenter(report)
2✔
117
    HTSSDProxyReportPresenter.new(report, controller: self, action: params[:action].to_sym)
10✔
118
  end
119

120
  # Filter param (if any) sent by Bootstrap Table translated into Hash.
121
  # This will be subsequently be translated into a form Ransack can understand.
122
  def filter
2✔
123
    @filter ||= JSON.parse(params.fetch("filter", "{}"))
1✔
124
  end
125

126
  # Translate Bootstrap Table filter fields and date start/end fields
127
  # into Ransack matchers
128
  def matchers
2✔
129
    return @matchers if @matchers
1✔
130

131
    @matchers = filter.transform_keys do |key|
1✔
132
      RANSACK_MATCHERS.fetch(key, key)
×
133
    end
134
    if params[:dateStart]
1✔
UNCOV
135
      @matchers[:datetime_gteq] = params[:dateStart]
×
136
    end
137
    if params[:dateEnd]
1✔
UNCOV
138
      @matchers[:datetime_lteq] = params[:dateEnd]
×
139
    end
140
    @matchers
1✔
141
  end
142
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc