开发者

How can I output a calculated value using .detect in Ruby on Rails? (or alternative to .detect)

I currently have the following code:

events.detect do |event|

#detect does the block until the statement goes false

  self.event_status(event) == "no status"

end

What this does is output the instance of event (where events is a string of different Models that all collectively call Events) when the event_status method outputs a "no status".

I would like the output to also include the value for delay where:

delay = delay + contact.event_delay(event)

event_delay method hasn't been written, but it would be similar (maybe redundant but I'll deal with that later) to event_status in looking at the delay be开发者_如何学Gotween when an event was done and when it was supposed to be done.

Here is how event_status looks currently for reference:

  def event_status target
  # check Ticket #78 for source

    target_class= target.class.name
    target_id   = target_class.foreign_key.to_sym

    assoc_name  = "contact_#{target_class.tableize}"

    r = send(assoc_name).send("find_by_#{target_id}", target.id) 
    return "no status" unless r
    "sent (#{r.date_sent.to_s(:long)})" 
  end

My concept of output should be [event,delay] so that, for example, I can access it as Array[:event] or Array[:delay] to get at the value.

****I was thinking maybe I should use yield on a method, but haven't quite put the pieces together (should the block passed to the method be the delay =+ for example, I think it is).**

I am not wed to the .detect method, it's what I started with and it appears to work, but it isn't allowing me to run the tally alongside it.


It's not entirely clear what you're asking for, but it sounds like you're trying to add up a delay until you reach a certain condition, and return the record that triggered the condition at the same time.

You might approach that using Enumerable#detect like you have, but by keeping a tally on the side:

def next_event_info
  next_event = nil
  delay = 0

  events.detect do |event|
    case (self.event_status(event))
    when "no status"
      true
    else
      delay += contact.event_delay(event)
      false
    end
  end

  [ next_event, delay ]
end

Update for if you want to add up all delays for all events, but also find the first event with the status of "no status":

def next_event_info
  next_event = nil
  delay = 0.0

  events.each do |event|
    case (self.event_status(event))
    when "no status"
      # Only assign to next_event if it has not been previously
      # assigned in this method call.
      next_event ||= event
    end

    # Tally up the delays for all events, converting to floating
    # point to ensure they're not native DB number types.
    delay += contact.event_delay(event).to_f
  end

  {
    :event => next_event,
    :delay => delay
  }
end

This will give you a Hash in return that you can interrogate as info[:event] or info[:delay]. Keep in mind to not abuse this method, for example:

# Each of these makes a method call, which is somewhat expensive
next_event = next_event_info[:event]
delay_to_event = next_event_info[:delay]

This will make two calls to this method, both of which will iterate over all the records and do the calculations. If you need to use it this way, you might as well make a special purpose function for each operation, or cache the result in a variable and use that:

# Make the method call once, save the results
event_info = next_event_info

# Use these results as required
next_event = event_info[:event]
delay_to_event = event_info[:delay]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜