Queue of callbacks Rails - ruby-on-rails

class Post < ActiveRecord::Base
has_many :comments, dependent: :destroy
before_destroy :post_method1
after_destroy :post_method2
end
class Comment < ActiveRecord::Base
belongs_to :post
after_destroy :comment_method
end
How will the callbacks and destroy methods be ordered in the two models after the post.destroy like (if post.comments.any? = true)???

Related

How cause association callback in rails models

How to track in the models this command
=> order = Order.create
=> order.items << Item.first // this command
if i have such models:
class Order < ApplicationRecord
has_many :order_items
has_many :items, through: :order_items
end
class Item < ApplicationRecord
has_many :order_items
has_many :orders, through: :order_items
end
class OrderItem < ApplicationRecord
belongs_to :order
belongs_to :item
end
I try use after_add for example, but I did not succeed.
For example my task:
In controller`s (OrderController) method create:
def create
#order = Order.create(order_params)
#order.items << Item.find(params[:id])
end
And i have that models Order or Item track this (when i add item to order) and print me message in console (for example)
Have a look at the Rails Guides about Association Callbacks. There is, for example, an after_add callback.
# in your Order model
has_many :items, after_add: :track_item_added
private
def track_item_added(item)
# your tracking code, for example
Rails.logger.debug("Item ##{item.id} added to order ##{id}")
end

Cart validations for maximum items

I have 2 models, cart and line_item:
cart.rb & line_item.rb
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
belongs_to :user
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :user
application_controller.rb
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = current_user.cart.create
session[:cart_id] = cart.id
cart
end
How can I add validations to my cart so that user can only add 5 items maximum into their cart? At the moment I have this code but it is not working?
def maximum_items_not_more_than_5
if line_items.count > 5
errors.add(:line_items, "must be less than 5")
end
end
Here is a way, I would try :
class LineItem < ActiveRecord::Base
belongs_to :cart, validate: true # enables validation
Then inside the Cart model, write your own custom validation like :
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
validate :maximum_items_not_more_than_5 # using custom validation
private
def maximum_items_not_more_than_5
if line_items.count > 5
errors.add(:base, "must be less than 5")
end
end
Why is line_item belonging to user?? Surely it would be item:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :carts
end
#app/models/cart.rb
class Cart < ActiveRecord::Base
belongs_to :user
has_many :line_items, inverse_of: :cart
has_many :items, through: :line_items
validate :max_line_items
private
def max_line_items
errors.add(:tags, "Too many items in your cart!!!!!!") if line_items.size > 5
end
end
#app/models/line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :cart, inverse_of: :line_items
belongs_to :item #-> surely you want to specify which item is in the cart?
end
#app/models/item.rb
class Item < ActiveRecord::Base
has_many :line_items
has_many :carts, through: :line_items
end
Validation
This is certainly in the realms of validation, specifically a custom method:
#app/models/model.rb
class Model < ActiveRecord::Base
validate :method
private
def method
## has access to all the instance attributes
end
end
I also put inverse_of into the mix.
You can see how this works here: https://stackoverflow.com/a/20283759/1143732
Specifically, it allows you to call parent / child objects from a particular model, thus allowing you to call validations & methods residing in those files.
In your case, it may be prudent to add validations to the line_item model -- specifying individual quantities or something. You can call the validations in this model directly from your cart model by setting the correct inverse_of

validate destruction of has_many association?

Models:
class Factory < ActiveRecord::Base
has_many :factory_workers
has_many :workers, through: :factory_workers
end
class FactoryWorkers < ActiveRecord::Base
belongs_to :factory
belongs_to :worker
before_destroy :union_approves?
private
def union_approves?
errors.add(:proletariat, "is never destroyed!")
false
end
end
class Worker < ActiveRecord::Base
has_many :factory_workers
has_many :factorys, through: :factory_workers
end
If I attempt to update a Factory's list of Workers via Factory, and that leads to the destruction of some FactoryWorker associations, I hope that the before_destroy hook is called, but this does not seem to be the case.
Example
Factory.create(name: 'communist paradise', worker_ids: [1, 2])
Factory.find_by(name: 'commnist paradise').update(worker_ids: [1])
# before_destroy hook is not called, proletariat must riot!
How can I ensure the before_destory hook is called when updating a record's associations?
Found what I needed: ActiveRecord provides a before_remove method on associations, so I just need to rejigger as follows:
class Factory < ActiveRecord::Base
has_and_belongs_to_many :workers, before_remove: :union_approves?
private
def union_approves?
...
end
end

Rails: avoid recursive destroy callbacks

I have two models:
class Car < ActiveRecord::Base
has_many :adverts, :dependent => :destroy
end
class Advert < ActiveRecord::Base
belongs_to :car
# Destroy the car, if there is no more adverts left
after_destroy do
self.car.destroy unless self.car.adverts.exists?
end
end
Now this works well when calling advert.destroy, but when calling car.destroy, things end up in a recursive loop!
PS. rails 4.1.8

How to know when the model is destoyed automatically by a :dependent => :destroy in rails?

I have the following association:
class Parent < ActiveRecord::Base
has_many :children, :dependent => :destroy
before_destroy :do_some_stuff
end
class Child < ActiveRecord::Base
belongs_to :parent
before_destroy :do_other_stuff
end
I would like to know in do_other_stuff if the destruction has been fired by dependent => destroy or not because part of it would/will be done in do_some_stuff
I tried parent.destroyed?, parent.marked_for_destruction?, parent.frozen? but nothing work :/
any ideas?
You can use the association callbacks ( before_remove or after_remove)
class Parent < ActiveRecord::Base
has_many :children, :dependent => :destroy, :before_remove => :do_foo
before_destroy :do_bar
def do_bar
end
def do_foo
end
end
Maybe something like that:
class Parent < ActiveRecord::Base
has_many :children
before_destroy :some_stuff
def some_stuff
children.each do |child|
child.parent_say_bye
end
end
end
class Child < ActiveRecord::Base
belongs_to :parent
before_destroy :do_other_stuff
def parent_say_bye
#do some stuff
delete
end
end

Resources