views:

243

answers:

2

Hi,

its the first time I post here. I have a problem that i can somehow not solve. Just for the record, I know what instance and class methods are (even if I may not understand them completely ;-) Here is my model code:

class Car < ActiveRecord::Base
has_many :drives
has_many :users, :through => :drives

def self.user_ids()
  ids = []
  self.users.each do |user|
    ids += user.id
  end
  ids
end

def self.common_times()
  start_times = []
  stop_times = []
  self.drives.each do |drive|
    drive.start_date_time += start_times
    drive.stop_date_time += stop_times
  end
  times = { :start => start_times.sort.last, :stop => stop_times.sort.first}
end

what I want is an array of all users using the car (which I use to check if a given user is already connected to the car for permissions etc.. Is there a better way to check if two datasets are already connected without doing SQL queries all the time?) and which start and stop times they prefer. I need than a hash with the latest starting time and the earliest stop time. Somehow the user_ids method works (even if I think it should be an instance method) and the common_times is always missing. if I define them both as an instance method I have problems with fixnum and array stuff (like "+").

user_id:
"TypeError: can't convert Fixnum into Array"

common_times:
"NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+"

I guess the best way is to make them instance methods. But then I need to refer differently to the other models as users and drives.

Why does user_ids work as an instance method even if declared as a class method?
How do I call already loaded models [c=Car.find(:all, :include => :drives)] inside an instance method?

Funny thing was also, that as long as they were class methods I could delete them and restart mongrel and they would still work (user_ids) and not work (common_times).

I am pretty confused right now and hop you can help me. And sorry for my bad english (I am german :-)

+3  A: 

Because of your users association, Rails already pre-builds the user_ids and users instance methods. Using @car.users should be your best bet.

As for instance and class methods: instance methods are for specific objects, whereas class methods are just put under the class name for your convenience. @car.id is an instance method, since it returns the ID of a single car. Cars.find is a class method, since it is independent of any single object and instead is grouped under the Cars class for organizational purposes. (It could just as easily be its own global find_cars method and work just as well, though it would be horrible design.)

So both of your methods should be instance methods, and the first one Rails creates for you because it loves you so much.

As for your individual errors, adding objects to an array is done with the << operator, not the plus sign. Ruby thinks you are trying to add two arrays, so is confused why you are trying to use a Fixnum in the same way you would typically use an array. Try making those fixes and see if you still get errors.

Matchu
Also, in self.common_times(), your arrays start_times and stop_times are always empty.
Reuben Mallaby
Thank you for the fast answer. So I changed the code to: def common_times() start_times = [] stop_times = [] drives.each do |drive| drive.start_date_time << start_times drive.stop_date_time << stop_times end times = { :start => start_times.sort.last, :stop => stop_times.sort.first} endbut now I still get the nil error: NoMethodError: You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.<< How do I have to call the drives in the method?
Luis
You still do nothing with start_times and stop_times so they are always empty -> [].sort.last == nil
Reuben Mallaby
Did you mean start_times << drive.start_date_time
Reuben Mallaby
drive.start_date_time << start_timesI guess that drives.each is empty
Luis
With your 'times = { :start => start_times.sort.last, :stop => stop_times.sort.first}', start_times and stop_times are always [], so you end up with times = {:start => nil, :stop => nil}
Reuben Mallaby
stupid me. Got it to work.. will post soonish
Luis
A: 

Got it to work (thnx @Matchu). Here is the final code for the method (no self-made user_ids anymore ;-)

def common_times()
  start_times = []
  stop_times = []
  drives.each do |drive|
    start_times << drive.start_date_time
    stop_times << drive.stop_date_time 
  end
  times = { :start => start_times.sort.last, :stop => stop_times.sort.first}
end 

the biggest error was the switched start_times << drive.start_date_time

Really silly error..

thanks again!

Luis
Once an answer works for you, be sure to click the check box next to it to make sure the poster gets credit :)
Matchu