views:

39

answers:

3

Here is my one model..

CardSignup.rb

def credit_status_on_create
  Organization.find(self.organization_id).update_credits
end

And here's my other model. As you can see what I wrote here is an incorrect way to pass the var

def update_credits
   @organization = Organization.find(params[:id])
   credit_count = @organization.card_signups.select { |c| c.credit_status == true}.count
end

If it can't be done by (params[:id]), what can it be done by?

Thanks!

A: 

Use an attr_accessor.

E.g.,

class << self
  @myvar = "something for all instances of model"
  attr_accessor :myvar
end
@myothervar = "something for initialized instances"
attr_accessor :myothervar

then you can access them as ModelName.myvar and ModelName.new.myvar respectively.

aharon
This is not thread safe solution.
KandadaBoggu
Unless he's using JRuby, it won't be really multithreaded anyway.
aharon
A: 

You don't say whether you're using Rails 2 or 3 but let's assume Rails 2 for this purpose (Rails 3 provides the a new DSL for constructing queries).

You could consider creating a named scope for in your Organization model as follows:

named_scope :update_credits,
            lambda { |id| { :include => :card_signup, :conditions => [ "id = ? AND card_signups.credit_status = TRUE", id ] } }

And then use it as follows:

def credit_status_on_create
  Organization.update_credits(self.organization_id)
end

Admittedly I don't quite understand the role of the counter in your logic but I'm sure you could craft that back into this suggestion if you adopt it.

bjg
+1  A: 

Ideally the data accessible to the controller should be passed as parameter to model methods. So I advise you to see if it is possible to rewrite your code. But here are two possible solutions to your problem. I prefer the later approach as it is generic.

Approach 1: Declare a virtual attribute

class CardSignup
 attr_accessor call_context
 def call_context
   @call_context || {}
 end
end

In your controller code:

def create
  cs = CardSignup.new(...)
  cs.call_context = params
  if cs.save
    # success
  else
    # error
  end
end

In your CardSignup model:

def credit_status_on_create
  Organization.find(self.organization_id).update_credits(call_context)
end

Update the Organization model. Note the change to your count logic.

def update_credits
  @organization = Organization.find(call_context[:id])
  credit_count = @organization.card_signups.count(:conditions => 
                  {:credit_status => true})
end

Approach 2: Declare a thread local variable accessible to all models

Your controller code:

def create
  Thread.local[:call_context] = params
  cs = CardSignup.new(...)
  if cs.save
    # success
  else
    # error
  end
end

Update the Organization model. Note the change to your count logic.

def update_credits
  @organization = Organization.find((Thread.local[:call_context] ||{})[:id])
  credit_count = @organization.card_signups.count(:conditions => 
                  {:credit_status => true})
end
KandadaBoggu