Вычисление диапазона строк в HTML-таблице вложенных ресурсов DataMapper

#ruby #haml #datamapper #erb

#ruby #haml #datamapper #ошибка

Вопрос:

У меня есть устаревшая база данных, которая находится за действительно дерьмовым PHP-приложением. Веб-приложение вызывает всевозможные проблемы с базой данных, и мне просто нужен быстрый способ представления того, что хранится в базе данных, таким образом, чтобы мой клиент мог видеть, насколько серьезна проблема, поэтому я создал приложение Sinatra DataMapper, но у меня возникли проблемы с вычислением некоторых значений в представлении.

В конце концов, я хочу таблицу, подобную этой:

                                              
  Profile   Registration   Signup   Payment  
                                             
                                    Payment  
                                             
                           Signup   Payment  
                                             
            Registration   Signup   Payment  
                                             
                           Signup             <- Signup w/ no payments
                                             
  Profile   Registration   Signup   Payment  
                                             
            Registration                      <- Registration w/ no Signups
                                             
  Profile                                     <- Profile w/ no Registrations
                                             
  

Моя первая проблема заключается в том, что для этого требуется тонна SQL-запросов [в основном (n 1) * (n 1) * (n 1) * (n 1)], но AFAIK нет способа заставить DataMapper выполнять быструю загрузку вложенных моделей или, в любом случае, кэшировать модель данных таким образом, чтобы чтение было более эффективным. (Я ничего не записываю обратно в БД, и снимок базы данных в порядке — на самом деле меня не волнуют текущие обновления). Пока это допустимо, потому что это одноразовый отчет.

Моя вторая проблема заключается в вычислении диапазона строк для заданных столбцов. Сначала я просто использовал количество платежей для текущей области ( profile.registrations.signups.payments.size , registration.signups.payments.size и т.д.), Но, как вы можете видеть в первом примере выше, на самом деле на один платеж меньше, чем потребовалось бы для получения точного диапазона строк для профиля.

Единственное теоретическое решение, которое я смог придумать, — это в основном перебирать каждый дочерний объект на каждом шаге по пути, чтобы точно выяснить, какие дочерние объекты доступны после этого шага, но это кажется действительно неэлегантным и потребовало бы экспоненциального увеличения выполняемого SQL.

Есть ли какой-либо другой способ, которым я могу подойти к этому? Я не женат на DataMapper или HAML, я просто хочу сделать это как можно эффективнее.

Я вставляю свой текущий HAML и модели данных ниже для справки.

index.haml (это неприятно, я знаю)

 #content
  %p #{@profiles.size} Profiles
  %table.display{:border=>1, :cellpadding=>2,:width=>'100%'}
    %thead
      %th Prof ID
      %th Profile
      %th Reg's
      %th Reg ID
      %th Registration
      %th Signups
      %th Event ID
      %th Event
      %th Event Date
      %th Payments
      %th Pmt ID
      %th Amt
      %th Pmt Date
    %tbody
      - @profiles.each do |profile|
        - profile_rowspan = [profile.registrations.signups.payments.size, profile.registrations.signups.size, profile.registrations.size, 1].detect { |i| i > 0 }
        %tr{:valign=>'top'}
          %td{:rowspan => profile_rowspan, :class => "profile"} #{profile.id}
          %td{:rowspan => profile_rowspan} #{profile.firstname} #{profile.lastname}
          %td{:rowspan => profile_rowspan} #{profile.registrations.size}
          - if profile.registrations.size == 0
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
            %td{:rowspan => profile_rowspan}
          - profile.registrations.each_with_index do |registration, reg_index|
            - if reg_index != 0
              != "</tr><tr valign="top">"
            - reg_rowspan = [registration.signups.payments.size, registration.signups.size, 1].detect { |i| i > 0 }
            %td{:rowspan => reg_rowspan, :class => "registration"} #{registration.id}
            %td{:rowspan => reg_rowspan} #{registration.firstname} #{registration.lastname}
            %td{:rowspan => reg_rowspan} #{registration.signups.size}
            - if registration.signups.size == 0
              %td{:rowspan => reg_rowspan}
              %td{:rowspan => reg_rowspan}
              %td{:rowspan => reg_rowspan}
              %td{:rowspan => reg_rowspan}
              %td{:rowspan => reg_rowspan}
              %td{:rowspan => reg_rowspan}
              %td{:rowspan => reg_rowspan}
            - registration.signups.each_with_index do |signup, signup_index|
              - if signup_index != 0
                != "</tr><tr valign="top">"
              - signup_rowspan = [signup.payments.size, 1].detect { |i| i > 0 }
              %td{:rowspan => signup_rowspan, :class => "signup"} #{signup.event.id}
              %td{:rowspan => signup_rowspan} #{signup.event.event_title}
              %td{:rowspan => signup_rowspan} #{signup.event.event_start}
              %td{:rowspan => signup_rowspan} #{signup.payments.size}
              - if signup.payments.size == 0
                %td{:rowspan => signup_rowspan}
                %td{:rowspan => signup_rowspan}
                %td{:rowspan => signup_rowspan}
              - signup.payments.each_with_index do |payment, payment_index|
                - if payment_index != 0
                  != "</tr><tr valign="top">"
                %td{:class => "payment"} #{payment.id}
                %td #{payment.total}
                %td #{payment.payment_date}
  

profile.rb

 class Profile
  has n, :registrations
end
  

registration.rb

 class Registration
  belongs_to :profile
  has n, :signups
  has n, :payments
end
  

регистрация.rb

 class Signup
  belongs_to :registration
  belongs_to :event
  has n, :payments
end
  

payment.rb

 class Payment
  belongs_to :registration
  belongs_to :signup
end
  

event.rb

 class Event
  has n, :signups
  has n, :payments, :through => :signups
end
  

Ответ №1:

Если вы используете MySQL, он может возвращать результаты запроса в формате HTML. Стоило бы посмотреть, что он может сделать в качестве отправной точки.

Затем вы могли бы использовать Nokogiri для поиска пустых ячеек и манипулирования HTML-кодом по своему усмотрению.