Hi! I have an app with products, categories, subcategories and resellercategories. Products.... belongs_to :resellercategory has_one :subcategory, :through => :resellercategory has_one :category, :through => :subcategory So, there are a lot of resellercategories that are (manually) mapped to my fewer subcategories. I have a before_save in my products model that sets if the product is complete: def check_complete self.complete = !image_small.blank? && !subcategory.blank? nil end So, if the resellercategory that the product is related to is mapped to a subcategory, the product is marked as "complete". However, at the moment it is only updated when the product is saved, I also want it to be updated when the resellercategory is mapped to a subcategory. Is there any good way to do this? Should I create an after_save in my resellercategory that iterates through all the products and re-saves all of them to get the field updated? Any easier/more effective way? Regards Linus -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/jtDjwL9A_WIJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
On Tue, Jan 3, 2012 at 11:14 PM, Linus Pettersson < linus.pettersson-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi! > > I have an app with products, categories, subcategories and > resellercategories. > > Products.... > > belongs_to :resellercategory > has_one :subcategory, :through => :resellercategory > has_one :category, :through => :subcategory > > So, there are a lot of resellercategories that are (manually) mapped to my > fewer subcategories. > > I have a before_save in my products model that sets if the product is > complete: > > def check_complete > self.complete = !image_small.blank? && !subcategory.blank? > nil > end > > So, if the resellercategory that the product is related to is mapped to a > subcategory, the product is marked as "complete". However, at the moment it > is only updated when the product is saved, I also want it to be updated > when the resellercategory is mapped to a subcategory. > > Is there any good way to do this? Should I create an after_save in my > resellercategory that iterates through all the products and re-saves all of > them to get the field updated? > Any easier/more effective way? >I am not sure I follow exactly, but ... Answer 1: I assume this " ... when the resellercategory is mapped to a subcategory ..." creates (or modifies) a ResellerCategory object (and saves it later to the database)? So as you suggest: "... Should I create an after_save in my resellercategory that ..." updates all associated products. Instead of "... iterates through all the products and re-saves all of them to get the field updated? ..." you could use an update_all , but that seems quite low-level database hacking (no models instantiated, no before/after filters ...). http://apidock.com/rails/ActiveRecord/Relation/update_all #untested code !! Product.where(:reseller_category_id => reseller_category.id).update_all(:complete => true) This does not feel comfortable, but it would probably work ... Answer 2: In reality, the Product.complete column is a de-facto cache for information that is already present in the database. Unless your have real performance problems associated with it, I would try to make a scope class Product < ActiveRecord::Base scope :complete ... that limits the products to those that are complete (that is, they have a category and a small_image). Then Product.complete.where. ... will inlcude the correct SQL to only select the complete products, _without_ the implicit caching problem that you are facing now. Very true:> There are only two hard things in Computer Science: cache > invalidation and naming things. > > Phil KarltonHTH, Peter -- Peter Vandenabeele http://twitter.com/peter_v http://rails.vandenabeele.com -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Thank you Peter. I have some follow up questions. Let''s say I would use a scope. How could I do that? (let''s ignore the "image_small" for now and focus on the subcategory) There is nothing in the product table that I can use to select the completed products. It is only regarded as completed if the related resellercategory is associated to a subcategory. So, in the scope I would need to join the resellercategories table and check if that is associated with a subcategory. Feels a bit unnecessary to do that for a small thing as this. But maybe it won''t affect the performance that much. The other option I was thinking of was just to add an after_filter in resellercategory model like this: def update_products self.products.each(&:save) end I''ll see if I can get the scope to work first. Regards Linus -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/kF4xK7oJ7UEJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
On Tue, Jan 3, 2012 at 11:55 PM, Linus Pettersson < linus.pettersson-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Thank you Peter. I have some follow up questions. > > Let''s say I would use a scope. How could I do that? (let''s ignore the > "image_small" for now and focus on the subcategory) There is nothing in the > product table that I can use to select the completed products. It is only > regarded as completed if the related resellercategory is associated to a > subcategory. So, in the scope I would need to join the resellercategories > table and check if that is associated with a subcategory. >Well, this article http://ablogaboutcode.com/2011/02/19/scopes-in-rails-3/ seems to indicate it can be done quite easily class User scope :by_age, lambda do |age| joins(:profile).where(''profile.age = ?'', age) unless age.nil? end scope :by_name, lambda{ |name| where(name: name) unless name.nil? } scope :by_email, lambda do |email| joins(:profile).where(''profile.email = ?'', email) unless email.nil? ... It joins user.profile to check on profile.age or profile.email ... I have not tested it, but seems not too difficult.> Feels a bit unnecessary to do that for a small thing as this. But maybe it > won''t affect the performance that much. >In my view, it is relevant, since it reduces the risk of cache inconsistency, which is a much harder problem to solve when your application grows. But I have had discussions with colleagues on this before and some actually preferred caching such implicit caching columns in local tables, to have simpler reporting on those tables later on (but the risk on inconsistency was always there).> > The other option I was thinking of was just to add an after_filter in > resellercategory model like this: > > def update_products > self.products.each(&:save) > end >Yes, this will work. But for any implicit caching option (also the update_all), you need to know all the models where the implicit product.complete cache is affected and have this cache update code there (currently that would only be the ResellerCategory model, but it can grow). The 3 options will work, but all have pros and cons: * Product :complete scope (no implicit caching) * Product update_all (sql level) * ResellerCategory after_save update_products (ActiveRecord level, but many queries) HTH, Peter -- Peter Vandenabeele http://twitter.com/peter_v http://rails.vandenabeele.com -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Thank you. I got the scopes working so now I can skip the extra field :) Best Regards Linus -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/_4K1YNttf5gJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.