Starkers
Starkers

Reputation: 10551

Save before initial save of an object

When a conversation is created, I want that conversation to have its creator automatically following it:

class Conversation < ActiveRecord::Base
    belongs_to :user
    has_many :followers
    has_many :users, through: :followers

    alias_method :user, :creator

    before_create { add_follower(self.creator) }

    def add_follower(user)

        unless self.followers.exists?(user_id: user.id)
            self.transaction do
                self.update_attributes(follower_count: follower_count + 1)
                self.followers.create(user_id: user.id)
            end
        end
    end

end

However, when a user attempts to create a conversation I get a stack level too deep . I'm creating an infinite loop, and I think this is because the before_create callback is being triggered by the self.update_attributes call.

So how should I efficiently update attributes before creation to stop this loop happening?

Upvotes: 0

Views: 70

Answers (1)

BroiSatse
BroiSatse

Reputation: 44705

Option 1 (preferred)

Rename your column follower_count to followers_count and add:

class Follower
  belongs_to :user, counter_cache: true
  # you can avoid renaming the column with "counter_cache: :follower_count"
  # rest of your code
end

Rails will handle updating followers_count for you.

Then change your add_follower method to:

def add_follower(user)
  return if followers.exists?(user_id: user.id)
  followers.build(user_id: user.id)
end

Option 2

If you don't want to use counter_cache, use update_column(:follower_count, follower_count + 1). update_column does not trigger any validations or callbacks.

Option 3

Finally you don't need to save anything at this point, just update the values and they will be saved when callback finishes:

def add_follower(user)
  return if followers.exists?(user_id: user.id)
  followers.build(user_id: user.id)
  self.follower_count = follower_count + 1
end

Upvotes: 1

Related Questions