如何在rails 4中为实例变量添加属性?

时间:2014-11-20 01:58:55

标签: ruby-on-rails ruby-on-rails-4 instance-variables

使用Rails 4,在控制器中我想为实例变量添加一个属性。

抱歉这个糟糕的例子,我试图保持简单。

E.g。在控制器中,我通过查找名为John的一些用户来创建一个新的实例变量。现在,在我的控制器中,我想总结所有名为John的用户的年龄,将这个总和年龄放回实例变量中,以便视图可用。

用户模型具有'id','name'和'age'属性。

@foo_users = Users.where(name: 'John')

@foo_users.each do |foo|
  @foo_users.age_sum = Users.where(name: 'John').sum(:age)  <-- this does not work
end

我没有必要将这个总计年龄保存回数据库,因为我只会在一个视图中使用它。我希望能够显示所有用户:

<% @foo_users.each do |user| %>
  User name: <%= user.name =>
  Sum of ages: <%= user.age_sum %>
<% end %>

更新:我可能过度简化了我的示例。这是一个更贴近现实的例子。

一家公司拥有酒店。酒店有房间。管理软件通过API向公司每日提供Hotel_Statistics。由于缺乏更好的词汇,这些Hotel_Statistics包含hotel_id,每日登记入住,每日退房。在我正在处理的公司的后台Rails应用程序中,在显示的页面上有一个酒店列表,其中包含最新的统计数据。一行看起来像:

Hotel Id: 123
Daily check-ins: 50 
Daily check-outs: 48

Hotel Id: 124
Daily check-ins: 35
Daily check-outs: 37

该公司还希望显示最近30天签到(出局,网上办理登机手续)的运行总额。 为了实现这一点,在我的控制器中,我找到了最近日期(通常是昨天)的Hotel_Statics。

latest_stat = HotelStatistic.order('date DESC, hotel_id DESC').first
@latest_date = latest_stat.date
@recent_stats = HotelStatistic.where(date: @latest_date).order('hotel.id ASC').all

我在视图中显示@recent_stats的详细信息。

现在,我想在我的视图中显示每个酒店@ last_stats.check_ins的最近30天的总和。我的想法是总结一下给定酒店的最后30天check_ins统计数据:

@recent_stats.each do |stat|
    @last_30_days_check_ins = HotelStatistic.where(hotel_id: stat.hotel_id).where("date >= ?", Date.today - 30).sum(:check_ins)
end

数学有效,但我需要一种方法来访问每家酒店的30天总和变量。我希望通过将酒店30天的总和添加到@recent_stats实例变量来使视图变得简单,所以在我看来我可以这样做:

<% @recent_stats.each do |statistic| %>
    Hotel Id: <%= statistic.hotel_id %>
    Daily check-ins: <%= statistic.check_ins %>
    Last 30 days check-ins: <%= statistic.last_30_days_check_ins %>     
<% end %>

这个更现实的例子是否会改变您建议的答案中的任何内容?感谢

2 个答案:

答案 0 :(得分:0)

使用select可以解决您的问题:

@users = User.select("*, SUM(age) as age_sum").where(name: 'John')

现在User数组中的每个@users都有一个age_sum属性。这并非100%理想,因为每个实例的属性值都相同,但它将与您设置视图的方式一致。

修改 可以手动动态定义实例上的方法:

@foo_users.each do |foo|
  def foo.age_sum; Users.where(name: 'John').sum(:age); end;
end

然而,虽然这是可能的,但它必须是一个非常好的用例来证明这可能产生的负面影响(例如代码的可读性,有效性和可维护性)。可能有更好的OO方法来解决同样的问题

答案 1 :(得分:0)

@foo_users的类型为ActiveRecord::Relation。尝试将age_sum作为新属性添加到ActiveRecord::Relation对象没有意义,因为语义age_sum不是ActiveRecord::Relation个对象的属性。最好将年龄总和存储在新的实例变量中,例如@user_age_sum

<强>更新 请尝试以下

class HotelStatistic < ActiveRecord::Base
  belongs_to :hotel
end

class Hotel < ActiveRecord::Base
  has_many :hotel_statistics

  def last_30_days_check_ins
    self.hotel_statistics.where("date >= ?", 30.days.ago).sum(:check_ins)
  end

end

保留用于在控制器中构建@recent_stats的现有代码

在视图中

<% @recent_stats.each do |statistic| %>
    Hotel Id: <%= statistic.hotel_id %>
    Daily check-ins: <%= statistic.check_ins %>
    Last 30 days check-ins: <%= statistic.hotel.last_30_days_check_ins %>     
<% end %>