has through

Hi,

I have 3 models

Product
  has_many :mutations

  def current_stock
<blablabla here I calculated the current stock of the product>
end

Mutation
  belongs_to :product
  belongs_to :location

Location
  has_many :mutations

Question:

I can show the currect stock of a product with

product.current_stock

but how do a walk through all locations and show the different current
stock of per location. I was thinkinf of using has many through and
the use something like product.current_stock.locations.each etc.

But ofcourse that does not work.

Who can help ?

Correct me if I’m wrong, but is this what you’re looking for?

Product

has_many :locations, :through => :mutations

end

Mutations

belongs_to :product

belongs_to :location

end

Location

has_many :products, :through => :mutations

end

product_stocks = Location.products.collect {|x| x.current_stock}

If you need the name you could do something like

Location.products.each { |product| products[product.name] = product.current_stock }

maybe a newbie question but what if I have a product ID and want to
show current_stock in the different locations?

First of all, I’m an idiot because I didn’t include something necessary to make it work
Both Product and Location should have has_many :mutations

Secondly, what you’re asking means you want to do something other than what you had in your original post: you want to have a current_stock for each product <-> location relationship… that means current_stock should be part of the Mutation model.

If you want to keep a total current_stock for each product, and a seperate one for each product at each location, then you would want to have current_stock in Location be the sum of the stocks for all the locations, which means your code should now look like:

class Location < ActiveRecord::Base
has_many :mutations
has_many :locations, :through => :mutations
def current_stock
Mutations.find_by_product_id(self.id).inject(0) {|total, location_stock| total += location_stock.current_stock}

end
end

class Mutation < ActiveRecord::Base
belongs_to :location
belongs_to :product
def current_stock
# code to figure out current stock for this product/location
end
end

class Location < ActiveRecord::Base
has_many :mutations
has_many :products, :through => :mutations
end

And if I weren’t an idiot, this would have said class Product instead of class Location at the top

I guess I am not being clear on what I am looking for :slight_smile:

What I want is for a product X (example: 24710089) to show the
current_stock in all locations. Show I should get some array/hash that
allows me to output

Product 24710089
          Location A: 10
          Location C: 20
etc.

Based on examples above this is what I have implemented now:

class Product < ActiveRecord::Base
  has_many :mutations
  has_many :locations, :through => :mutations

  def current_stock
    Mutation.find_all_by_product_id(self.id).inject(0) {|total, mut|
total += mut.mutation}
  end
end

class Mutation < ActiveRecord::Base
  belongs_to :product
  belongs_to :location

  def mutation
    mutation = 0 + self.buy - self.sell - self.transit - self.lost
  end
end

class Location < ActiveRecord::Base
  has_many :mutations
  has_many :products, :through => :mutations

  def current_stock
      Mutation.find_all_by_location_id(self.id).inject(0) {|total,
mut> total += mut.mutation}
  end

end

So the solution I am looking for should allow me to input the
product_id as the selection criteria then return all locations with
the current_stock value. Any tips ?

I guess I am not being clear on what I am looking for :slight_smile:

What I want is for a product X (example: 24710089) to show the
current_stock in all locations. Show I should get some array/hash that
allows me to output

Product 24710089
Location A: 10
Location C: 20
etc.

Ahh… I thought you wanted to be able to have stock at each location, and then have the total stock (which is what product.current_stock does right now). I’m going to go ahead and leave that alone, and show you another function that will do what you want (that way you can do either one)

class Product < ActiveRecord::Base
has_many :mutations
has_many :locations, :through => :mutations

def current_stock
Mutation.find_all_by_product_id(self.id).inject(0) {|total, mut|

total += mut.mutation}
end
end

def location_stocks
Mutation.find_all_by_product_id(self.id).each {|m| location_stock[m.location_id] = m.mutation}
location_stock

end

Now let’s say you have two locations, location1 and location2.
location1’s id = 14839, current stock = 24
location2’s id = 19248, current stock = 94
If each of those locations had product 24710089 in it, and you did

l = Product.find(24710089).location_stocks
then
l[14839] == 24
l[19248] == 94
Or, in Ruby parlance
l == {14839 => 24, 19248 => 94}

Will that do what you want?

class Mutation < ActiveRecord::Base
belongs_to :product
belongs_to :location

def mutation
mutation = 0 + self.buy - self.sell - self.transit - self.lost
end
end

class Location < ActiveRecord::Base

has_many :mutations
has_many :products, :through => :mutations

You probably don’t want current_stock here, unless you want it to show the stock of all the products at this location

If you do, it’s:
def current_stock
Mutation.find_all_by_location_id(self.id).each {|m| product_stock[m.product_id] = m.mutation}
product_stock
end
This will be
product_stock == {24710089 => 24} for location1

and
product_stock == {24710089 => 94} for location2