计算嵌套DataMapper资源的HTML表中的rowspan

时间:2011-04-16 19:43:58

标签: ruby haml datamapper erb

我有一个遗留数据库,它位于一个非常糟糕的PHP应用程序后面。 Web应用程序引起了数据库的各种问题,我只需要一种快速而又脏的方式来表示存储在数据库中的内容,以便我的客户端可以看到问题有多严重,所以我构建了一个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急切地加载嵌套模型,也无论如何以一种使读取更有效的方式缓存数据模型。 (我没有写任何东西回到数据库,数据库的快照很好 - 不关心实时更新)。现在这是可以忍受的,因为这是一次性报告。

我的第二个问题是计算给定列的rowspan。起初我只是使用了当前范围的付款次数(profile.registrations.signups.payments.sizeregistration.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

signup.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 个答案:

答案 0 :(得分:0)

如果您使用的是MySQL,它可以将查询结果作为HTML返回。值得看看它能做什么作为起点。

然后,您可以使用Nokogiri查找空单元格并根据需要操作HTML。