Shpigford
Shpigford

Reputation: 25328

Issue with association creates

Here are my associations...

Account has_many :credits
Credit belongs_to :account

And I'm trying to run: account.credits.current

So, in that case, I've already got an Account object, and then I want to access a current method within the Credit model.

Here is that method...

def self.current
   # Find current credit line
   current = self.where(:for_date => Time.now.strftime("%Y-%m-01")).first

   # If we couldn't find a credit line for this month, create one
   current = Credit.create(:account_id => self.account.id, :for_date => Time.now.strftime("%Y-%m-01")) if current.blank?

   # Return the object
   current
end

The problem is on that second line...the one that should create a new credit entry if it can't find one. Specifically, I can't set what account it should be associated with. I just get an undefined method 'account' error.

Upvotes: 3

Views: 79

Answers (2)

user419017
user419017

Reputation:

Create through association instead, and leave out the account_id as it will be linked automatically:

current = self.create(:for_date => Time.now.strftime("%Y-%m-01")) if current.blank?

Note: self.create instead of Credit.create.

Upvotes: 1

Andrew
Andrew

Reputation: 43103

You're trying to access instance properties in a class method, that's not possible.

If you have this:

class Credit
   def self.current
      self.account
   end
end

It's the same as: Credit.account, which as I'm sure you understand, would not work.

Now, your method current has to be a class method if you want it to load on the plural association: ie:

With def self.current you can call account.credits.current

With def current you can call account.credits[0].current or account.credits.where(...).current

I hope this makes sense. Now, as for what to do about it...

My recommendation would be to make current a scope, like so:

class Credit
  scope :current, lambda { where(:for_date => Time.now.strftime("%Y-%m-01")).first }
  ...
end

Then you can use this scope anywhere and have an instance (or nil) at the end of it.

account.credits.create(...) unless accounts.credit.current

If you want to make a convenience method, I would then do:

class Credit def self.current_or_new self.current || self.create( :for_date => Time.now.strftime("%Y-%m-01") ) end end

This should work the way you are intending. If it's called through an association, ie:

account.credits.current_or_new

Then the account_id will be put in for you by rails through the association.

Upvotes: 0

Related Questions