【问题标题】:aggregate conditional has_many rails association聚合条件 has_many rails 关联
【发布时间】:2010-02-28 16:25:14
【问题描述】:

我不确定这是否可行甚至更可取

但我想建立一个 has_many 关系或一个有条件的 named_scope 类型关系,以减轻我对一个简单关系而不是两个关系的痛苦。

目前我有两个模型,它们基本上包含相同的信息,并且通过相同的 key room_id 属于相同的模型房间,但以两种不同的方式保存数据。一个包含特定日期的特定信息,第二个包含一周中几天的通用费率。主要障碍是,Availables 可能根本不包含特定记录的信息,在这种情况下,它需要根据 room_rates 来获取平均价格,而不是给定日期的具体价格。

有什么建议或建议吗?谢谢

可用的

+--------+-------+-------+------------+---------+-----+
| id     | price | spots | bookdate   | room_id | min |
+--------+-------+-------+------------+---------+-----+
| 180315 | 14.4  | 1     | 2010-02-27 | 2517    | 1   |
| 231726 | 15.84 | 1     | 2010-03-24 | 2517    | 1   |
| 180311 | 14.4  | 1     | 2010-02-23 | 2517    | 1   |
| 180313 | 14.4  | 1     | 2010-02-25 | 2517    | 1   |
+--------+-------+-------+------------+---------+-----+

Room_rates

+-------+---------+-----------+-------+-----+
| id    | room_id | dayofweek | price | min |
+-------+---------+-----------+-------+-----+
| 87936 | 2517    | 0         | 14.58 | 1   |
| 87937 | 2517    | 1         | 14.58 | 1   |
| 87938 | 2517    | 2         | 14.52 | 1   |
| 87939 | 2517    | 3         | 14.52 | 1   |
| 87940 | 2517    | 4         | 14.52 | 1   |
| 87941 | 2517    | 5         | 14.4  | 1   |
| 87942 | 2517    | 6         | 14.63 | 1   |
+-------+---------+-----------+-------+-----+

或者可能是 finder_sql 方法?如:

  has_many :aggregates,
           :class_name => 'Available',
           :finder_sql => 'SELECT room_id, price, spots, bookdate, MIN(source) 
           FROM availables
           WHERE room_id = #{id}
           GROUP BY room_id, price, spots, bookdate'

但它还需要通过加入 room_rates 来填补不存在的 bookdates 的缺失记录

【问题讨论】:

  • 只是为了在思考的同时更好地理解:如果Availables中没有条目,那是否意味着没有可用的东西?在其他哪些情况下,Availables 中没有条目会发生? “特定记录的信息”中的“记录”是指room_id的记录,对吗?
  • 嗯,在可用的特定房间价格有多个来源......而且它可能完全丢失但仍然可用。如果是淡季,则来源几乎没有理由更新,它会退回到 room_rates 表中。如果房间真的不可用,在大多数情况下,它会有一个可用记录,其中“spots” = 0 在该特定日期。
  • 这就是为什么我希望有一些 has_many 魔法或某种范围来从源头上处理我所有的问题。就目前而言,我有很多逻辑过于分散。

标签: ruby-on-rails ruby named-scope has-many has-many-through


【解决方案1】:

您可以在一个 sql 中执行此操作。但它需要你执行一个相当大的 SQL。另一方面,您可以在一个带有排序和其他好处的语句中获得结果。

免责声明 1:此代码是农场新鲜的、空气编码的,未经过任何有害测试。

免责声明 2:availables 表中的同一房间在日期 2010-02-25 有 2 行。我假设这是一个失常。否则,您需要向 select 语句传递一个附加参数以进一步过滤结果。

class Available < ActiveRecord::Base  
  def self.daily_rates room_id, from_date, to_date 
    date_table = (from_date..to_date).collect do |date| 
      "(SELECT  #{room_id} AS room_id, '#{date.to_formatted_s(:db)}' AS bookdate )"
    end.join(" UNION ")

    ActiveSupport::OrderedHash.new.tap do |hash|
      Available.find_by_sql( " 
         SELECT A.bookdate, IFNULL(B.price, C.price) AS price
         FROM   (#{date_table}) A
         LEFT OUTER JOIN availables B 
                ON A.room_id = B.room_id AND A.bookdate = B.bookdate
         JOIN room_rates C 
                ON A.room_id = C.room_id AND DAYOFWEEK(A.bookdate) = C.dayofweek + 1
         ORDER BY A.bookdate ASC"
      ).each do |rate_info |
        hash[rate_info.bookdate] = rate_info.price
      end
    end
  end  

end

现在您可以拨打电话,例如:

rates = Available.daily_rates(1, '2010-02-23'.to_date, '2010-02-27'.to_date)

rates.keys[0]   # Tue, 23 Feb 2010
rates.values[0] # 14.3999996185303

让我们检查availables 表中缺少的 26 日的汇率。

rates.keys[3]   # Tue, 26 Feb 2010
rates.values[3] # 14.3999996185303

【讨论】:

  • 有趣的想法,但现在我想知道是否可以使用 finder_sql 方法做类似的事情。这样我就可以使用标准的 has_many...
【解决方案2】:

我只是将方法添加到 Room 模型。我假设您想获取特定日期的价格。

def get_price(date)
  (self.availbles.find_by_bookdate(date) || self.room_rates.find_by_dayofweek(dayofweek(date)) ).price
end

您需要将dayofweek(date) 替换为可以为您提供特定星期几的内容。这将从availbles 返回price,如果没有这样的行,则从room_rates 返回。如果两行都缺失,您将遇到错误。我希望它能给你一些想法如何解决这个问题。

如果有一系列日期,我会添加另一种方法:

def get_prices(start_date, end_date)
  dates = (start_date..end_date).to_a
  prices = {}
  dates.each do |d|
    prices[:d] = get_price(d)
  end
  prices
end

它将以日期为键的价格返回哈希

【讨论】:

  • 但是,如果我想要获得的不仅仅是一个单独的日期,而是获得一系列日期,其中一些来自可用日期,然后由 room_rates 填充,该怎么办?
  • @holden:我添加了日期范围的解决方案。
  • 您也可以尝试从availble加载所有价格,然后将其映射到hash并用room_rates中的数据填充nil。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多