johan
johan

Reputation: 721

how to compare entry from the previous

I have a table of consumptions

  create_table "consumptions", force: :cascade do |t|
    t.float "kilometers"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "user_id"
  end

Here is a list of consumptions for user 1

 #<Consumption:0x007f8654895080     
  id: 1,
  kilometers: 10000.0,
  created_at: Wed, 07 Nov 2018 15:23:21 UTC +00:00,
  updated_at: Wed, 07 Nov 2018 15:23:21 UTC +00:00,
  user_id: 1>,
 #<Consumption:0x007f865489c268
  id: 4,
  kilometers: 10800.0,
  created_at: Wed, 24 Oct 2018 14:30:23 UTC +00:00,
  updated_at: Thu, 08 Nov 2018 12:35:37 UTC +00:00,
  user_id: 1>,
 #<Consumption:0x007f8654893f50
  id: 6,
  kilometers: 11400.0,
  created_at: Thu, 08 Nov 2018 11:56:52 UTC +00:00,
  updated_at: Thu, 08 Nov 2018 12:36:42 UTC +00:00,
  user_id: 1>,

I want to compare the difference of kilometers between each consumption...

consumptions

id |   km  | 
1  | 10000 | 
4  | 10800 | 
6  | 11400 | 

Result between id 1 and 4 should be 800

Result between 4 and 6 should be 600

Upvotes: 0

Views: 51

Answers (4)

johan
johan

Reputation: 721

I found an easier way:

So I added an attribute difference set by default to 0 to consumptions

class Consumption < ApplicationRecord
    belongs_to :user

    before_save :count_difference

    def count_difference
        if Consumption.any?
            if Consumption.last.user_id == self.user_id
                self.difference = Consumption.last.kilometers - self.kilometers
            end
        end
    end

end

Upvotes: 0

Mark
Mark

Reputation: 6455

To give more of a 'ruby' answer:

def difference_in_km(obj_1, obj_2)
  (obj1.kilometers - obj2.kilometers).abs
end

The abs is there to handle negative figures, returning 400 instead of -400 for example.

This lets you do:

con_1 = Consumption.find(1)
con_2 = Consumption.find(4)

difference_in_km(con_1, con_2)

Another approach would be to add an instance method to your Consumption class:

class Consumption < ApplicationRecord
  ....
  ....

  def distance_from(other_consumption)
    (kilometers - other_consumption.kilometers).abs
  end
end

This will allow you to do:

con_1.distance_from(con_2)

Upvotes: 0

Federico
Federico

Reputation: 58

I would recommend you to take a look at https://github.com/geokit/geokit-rails You just need to add acts_as_mappable to your model (decide if you config your default values or place them in your model, I think the best would be to do it on a config file).

Then you just use by_distance method and your code would look so much nice :)

Upvotes: 1

richflow
richflow

Reputation: 2144

What database are you using?

Basically, you want to use a window function:

E.g. for PostgreSQL:

select id, kilometers - lag(kilometers) over (order by id) as difference? from consumptions;

PostgreSQL reference

MySQL reference

Another example on SO

You could then use find_by_sql to retrieve the value as an ActiveRecord model, suggested here.

The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from.

I haven't tried it but yours would look like:

Consumptions.find_by_sql('select id, kilometers - lag(kilometers) over (order by id) as difference? from consumptions')

Upvotes: 0

Related Questions