Reputation: 2200
So i'm fairly new to rails and ActiveRecord
and I have a need for a scope to filter between Client
entities. Basically the scope should return all Client
records where the client's current state is equal to a certain state object.
This is calculated by getting a client's last state_change
and then pulling that state_change
's from_state
which is a State
object.
I have defined a method to return the current_state
however in rails console when I test it with Client.current_state(Client.last)
I get this error:
NameError: undefined local variable or method 'state_changes for #<Class:0x0000000685eb88>
but when running Client.last.state_changes
in console it works fine.
My client.rb
class Client < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :industry
belongs_to :account
has_many :contacts
has_many :state_changes
belongs_to :head, class_name: "Client"
has_many :branches, class_name: "Client", foreign_key: "head_id"
has_many :meetings, through: :contacts
has_many :sales, through: :meetings
scope :prospects, -> (client) { where(Client.current_state(client): State.PROSPECT_STATE) }
def self.has_at_least_one_sale? (client)
return client.sales.empty?
end
def self.has_account_number? (client)
return client.account_number.present?
end
def self.current_state (client)
state_changes.last.to_state
end
end
state_change.rb
class StateChange < ActiveRecord::Base
belongs_to :client
belongs_to :from_state, class_name: "State", foreign_key: :to_state_id
belongs_to :to_state, class_name: "State", foreign_key: :from_state_id
end
state.rb
class State < ActiveRecord::Base
has_many :from_states, class_name: "StateChange", foreign_key: :to_state_id
has_many :to_states, class_name: "StateChange", foreign_key: :from_state_id
def self.PROSPECT_STATE
return State.find_by name: 'Prospect'
end
def self.CLIENT_STATE
return State.find_by name: 'Client'
end
def self.SUSPECT_STATE
return State.find_by name: 'Suspect'
end
end
I also get syntax errors regarding the scope I defined in client.rb. I have followed the ActiveRecord
guide but they don't explain how to have chained methods in the actualy scope query.
Upvotes: 3
Views: 7010
Reputation: 5802
The reason you get the error NameError: undefined local variable or method 'state_changes for #<Class:0x0000000685eb88>
is because you define current_state
as a class method and pass the client as a parameter. That's why state_changes
is called on the class and not the instance. In this case you would need to use the client to get the state_changes
.
def self.current_state (client)
client.state_changes.last.to_state
end
Also scopes are meant to just chain query logic. I'm not sure if it is possible to just use queries to get your wanted result. And I hope I understood your logic correctly. Alternatively you could use a class method.
def self.prospects (client)
Client.all.select { |c| c.current_state(c) == State.PROSPECT_STATE }
end
As pointed out by Зелёный in the comment, maybe you also want to just change the methods to instance methods, in which case reading the resource he linked would be very helpful.
Update based on comment:
I think what you actually want is using an instance method for current_state
like this:
def current_state
state_changes.last.to_state
end
And then you can get prospects like this:
def self.prospects
Client.all.select { |c| c.current_state == State.PROSPECT_STATE }
end
Upvotes: 5