在Rails中添加和人性化时间

时间:2014-08-29 14:30:58

标签: ruby-on-rails ruby model-view-controller methods

我有一个专辑模型,每张专辑有很多曲目:

#app/models/album.rb
class Album < ActiveRecord::Base
  has_many :tracks
end

#app/models/album.rb
class Track < ActiveRecord::Base
  belongs_to :album
end

每个单独的曲目都有一个模型类型为时间的持续时间。为了显示每个专辑的所有曲目,我按如下方式设置了我的节目动作:

#app/controllers/albums_controller.rb
def show
  @tracks = @artist.tracks.all
end

更新:显示我的_form.html.erb中存储的持续时间

#app/views/tracks/_form.html.erb
<div class="field">
  <%= f.label :duration %><br>
  <%= f.time_select :duration, include_seconds: true, default: {hour: '00', minute: '01', second: '30'} %>
</div>

-

这是问题发生的地方。我基本上想要将所有轨道持续时间加在一起,并以人类可读的格式显示它们。例如,专辑 Total Runtime 将是1小时13分钟。我将持续时间加在一起的第一直觉是使用注入方法:

#apps/views/albums/show.html.erb
.
.
.
<% @tracks.inject(0) {|sum, track|  track.duration.to_s(:time) + sum} %>
  • 我最终收到此错误:no implicit conversion of Fixnum into String

  • 我的第二个问题是进一步配置to_s(:time)方法。轨道通常显示如下:3:30,意思是(x)分钟:(x)秒。不幸的是,to_s(:time)限制您只显示小时和分钟,我只需要几分钟和几秒钟。

  • 最后得到总持续时间我并不完全确定这样做的最佳方法。有没有办法将inject方法的结果保存为名为 runtime 的变量并将其包装成这样,同时删除distance_of_time_in_words附带的 About 文本方法

<p><b>Total Runtime:</b><%= runtime.distance_of_time_in_words %></p>

1 个答案:

答案 0 :(得分:0)

这是一个冗长的例子:

app/models/concerns/time_format.rb

# module to contain method used by both Album and Track
module TimeFormat
  extend ActiveSupport::Concerns

  def to_time(total_time)
    minutes, seconds = total_time.to_i.divmod(60)
    return [minutes, seconds]
  end
end

app/models/track.rb

class Track < ActiveRecord::Base
  include TimeFormat
  belongs_to :album
  attr_accessor :minutes, :seconds
  validates :length, :minutes, :seconds, numericality: {only_integer: true}
  before_update :to_seconds

  minutes, seconds = to_time(length)

  def to_seconds
    length = (minutes * 60) + seconds
  end
end

希望这会指出你正确的方向:

app/models/album.rb

class Album < ActiveRecord::Base
  include TimeFormat
  has_many :tracks
  attr_accessor :length, :minutes, :seconds
  validates :length, :minutes, :seconds, numericality: {only_integer: true}

  def calculate_length
    self.tracks.each do |track|
      length += track.length
    end
  end

  minutes, seconds = to_time(self.calculate_length)

end

app/controllers/albums_controller.rb

# If your controller was generated with scaffolding, no need to change the `show` method.
# It should already be loading an album object for you via the `before_action` callback.
# The only thing to make sure is that you change accepted parameters for the create and
# update methods (do the same thing in Tracks if you need to).

def album_params
  params.require(:album).permit(:minutes, :seconds, <other params>...)
end

app/views/tracks/_form.html.erb

# You can use this same field in your Album view.

<div class="field">
  <%= f.label :minutes %><br>
  <%= f.number_field :minutes  %>
  <%= f.label :seconds %><br>
  <%= f.number_field :seconds %>
</div>

我还不是经验丰富的Rails开发人员,所以这些例子中可能有些部分可以缩减,但我希望这能传达一般意义!