I am trying to save an array of multiple ids (item_variation_ids) to a model called items_stock from item variations model. In a column called item_variation_ids in item_stock, it is saving the ids like [1,2,3] for twice. I want the item_variation_ids to be saved once only with 1,2,3 in a single column.
My item_variation model
#app/models/item_variation
class ItemVariation < ApplicationRecord
belongs_to :item
validates_associated :item
after_save :add_to_item_stock
def add_to_item_stock
ItemStock.create(item_variation_ids: ItemVariation.ids, items_id: items_id)
end
end
My item model
#app/models/item
class Item < ApplicationRecord
has_many :item_variations, foreign_key: :items_id
has_many :item_stocks, foreign_key: :items_id
accepts_nested_attributes_for :item_stocks
end
My item_stock model
#app/models/item_stock
class ItemStock < ApplicationRecord
belongs_to :item
end
But how do you know which ItemVariation ids should go on that ItemStock? and you are creating one ItemStock each time any variation gets saved. I don't even think you need to set that ids array since the ItemStock already belongs to an Item which has many variations (#item_stock.item.variations and you are done).
Also now you are talking about a stock_qty attribute you never mentioned before, you are never setting it on the callback and you didn't show your database schema. where does that amout come from? is an attribute on the variation that you want to sum to the current item_stock?
I also don't understand why an item has many item stocks for the code you are showing.
I'll do a wild guess and suggest you do something like:
ItemStock
belongs_to :item
belongs_to :item_variation
end
ItemVariation
after_save :add_to_item_stock
def add_to_item_stock
item_stock = self.item.item_stock.where(item_variation_id: self.id).first_or_initialize
item_stock.stock_qty = self.stock_qty
item_stock.save
end
end
but as I said, it's a wiiiiild guess. I'd recommend you to first try to understand what you are doing, because it seems like you just copied to code from that question you linked and you are no actually understanding it.
Related
For example, have the models:
class Activity < ActiveRecord::Base
belongs_to :event
end
class Event < ActiveRecord::Base
has_many :activities
attr_accessible :foo
end
I can get the activity's event foo by using activity.event.foo (simple enough).
But I want to make a generic function that finds out first if an object has a belongs_to association and then get that object's foo through the belongs_to association (pretend that all objects have a foo through the belongs_to association)?
So far I have the following with gives me a reflection:
def get_foo(object)
object.class.reflect_on_all_associations(:belongs_to).each do |belongs_to|
return object.??????
end
end
I can either get an array of the reflection's class name via belongs_to.klass (e.g. [Event]) or an array of symbols for the belongs_to association via belongs_to.name (e.g. [:event]).
How do I get the object's belongs_to's foo given what I get from the reflection?
Is there an easier way to do this without using the reflection?
I'm hoping this is something simple and I'm just spacing out on how to solve this. I also hope I am being somewhat clear. This is my first Stack Overflow question.
You can do this but its not exactly pretty:
def get_foo(object)
object.class.reflect_on_all_associations(:belongs_to).map do |reflection|
object.send(reflection.name).try(:foo)
end
end
That will give you an array of all the foos associated with the object. You can change it to not do map and do a first or something.
product.rb
has_many :votes
vote.rb
belongs_to :product
Every time, i use sorting in my index controller:
index_controller.rb
def index
#products = Product.all.sort { |m| m.votes.count }
end
So, i think it would be good to cache votes count for each product (create additional column votesCount in products table)?
If yes, can i preform that using before_save and before_delete callbacks in vote.rb model?
Or what is the best practice method?
Give me some examples please.
I guess you are looking for counter_cache
The :counter_cache option can be used to make finding the number of belonging objects more efficient
Consider these models:
class Order < ActiveRecord::Base
belongs_to :customer, counter_cache: true
end
class Customer < ActiveRecord::Base
has_many :orders
end
With this declaration, Rails will keep the cache value up to date, and then return that value in response to the size method.
Although the :counter_cache option is specified on the model that includes the belongs_to declaration, the actual column must be added to the associated model. In the case above, you would need to add a column named orders_count to the Customer model
Associations:
class Foo
has_many :foo_subscribers
end
class FooSubscriber
belongs_to :foo
belongs_to :user
end
class User
has_many :foo_subscribers
belongs_to :employee
end
class Employee
has_one :user
end
The following code is adding a User object to the array, despite the explicit call to User's Employee
#foo.rb
employees_to_notify = Array.new
foo_subscribers.each do |user|
employees_to_notify << user.employee
end
All of the appropriate data is present for the test. Through debugging, I can evaluate user.employee as an employee object right on the line where it's added to the array.
How is this possible? I've tried various things like iterating over the array and converting any User objects to Employees. That also failed.
It looks like you are iterating over foo_subscribers, but then naming them as users in the pipes? Are foo_subscribers users?
I was trying to get foo_subscriber.employee rather than foo_subscriber.user.employee. I was attempting to perform an operation on the wrong type.
Assuming
class Kid < ActiveRecord::Base
has_one :friend
end
class Friend< ActiveRecord::Base
belongs_to :kid
end
How can I change this to
class Kid < ActiveRecord::Base
has_many :friends
end
class Friend< ActiveRecord::Base
belongs_to :kid
end
Will appreciate your insight...
Collection
The bottom line is that if you change your association to a has_many :x relationship, it creates a collection of the associative data; rather than a single object as with the single association
The difference here has no bearing on its implementation, but a lot of implications for how you use the association throughout your application. I'll explain both
Fix
Firstly, you are correct in that you can just change your has_one :friend to has_many :friends. You need to be careful to understand why this works:
ActiveRecord associations work by associating something called foreign_keys within your datatables. These are column references to the "primary key" (ID) of your parent class, allowing Rails / ActiveRecord to associate them
As long as you maintain the foreign_keys for all your Friend objects, you'll get the system working no problem.
--
Data
To expand on this idea, you must remember that as you create a has_many association, Rails / ActiveRecord is going to be pulling many records each time you reference the association.
This means that if you call #kind.friends, you will no longer receive a single object back. You'll receive all the objects from the datatable - which means you'll have to call a .each loop to manipulate / display them:
#kid = Kid.find 1
#kid.friends.each do |friend|
friend.name
end
If after doing this changes you have problem calling the save method on the order.save telling you that it already exists, and it not allowing you to actually have many order records for one customer you might need to call orders.save(:validate=> false)
You have answered the question. Just change it in model as you've shown.
I've got models called answers, surveys, questions. Now in a survey, there can be up to 200 questions and so one survey can generate up to 200 answer-models in a page.
The question is: How can I save the array of answers I have in a single db-action and not iterate over the array and save each element individually, which takes a lot of time relatively?
You can pass the 'belongs_to' relationship an :autosave symbol. This will cause the answers to be automatically saved when you save the parent. Something like this then would probably be what you want:
class Survey < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :survey, :autosave
has_one :answer
end
class Answer < ActiveRecord::Base
belongs_to :question, :autosave
end
I don't know how exactly this will perform behind the scenes, but it will allow ActiveRecord to optimise the SQL and removes the need for you to iterate explicitly over the relationships.
No matter what you do, don't forget to wrap your multiple inserts in a transaction. Will really speed things up.