0

I'm a novice in ruby-on-rails.

I have an applications counting distance between metro station and a ATM. There's two models with many-to-many relation: Station, Cashpoint. And there's a controller SHOW, that should get the station and show ATMs in order there's proximity to the station.

class StationsController < ApplicationController
    def show
        @station = Station.find(params[:id])
        @cashpoints = @station.cashpoints.find(:all)

         respond_to do |format|
            format.html 
         end    
    end
end

Also there's a helper that counts distance using Google Directions API.

module StationsHelper
    def count_distance(origin,destination)
         ...
        return {:text => ... # 1 min
                , :value => ... # 60 (seconds)
                }
    end
end

All this works properly.

But I'm wondering how to order ATMs by :value returned by StationsHelper?

I tried to write something in controller similar to:

@cashpoints = @station.cashpoints.find(:all, 
:order => count_distance(@station.address, cashpoint.address)[:value])

But it's evidently doesn't work 'cause I have know idea how to link single cashpoint object to count_distance method parameter.

May be you can help me, it appears that my project structure is wrong to do this.

lich
  • 290
  • 1
  • 5
  • 10

1 Answers1

0

Try this:

@cashpoints = @station.cashpoints.find(:all).sort_by { |c| count_distance(c.address, @station.address) }
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • method count_distance is defined inside StationsHelper, so this doesn't work (I get error: undefined method `count_distance' for #). May be I should move this method from helper to the controller. How should I envoke it in this case? – lich Jul 26 '11 at 08:42
  • Try defining it in ApplicationController, and then making it a helper method by doing `helper :count_distance`. – Dogbert Jul 26 '11 at 09:03
  • I would recommend to move the method to the `Station` model to get to the logic: a Station knows the distance to any other Station. Then do the sort like `@cashpoints = @station.cashpoints.find(:all).sort_by { |c| @station.distance_to(c) }` – arnep Jul 26 '11 at 11:17
  • I also think that it should be in the model. But @arnep, it's not a distance between objects of one class, it's a distance between objects of different classes. Like a class Trip with one-to-one relation with Cashpoint and Station. But should it relate to ActiveRecord::Base somehow? I don't need to store such data in database. – lich Jul 26 '11 at 11:28
  • @lich you do not need both objects of the same model to calculate the distance. The parameter for `distance_to` can be a Station. Also adding methods to a model does not mean to store anything in the database. Apropos storing in the database: the Google Directions API says you should cache the data you retrieve. – arnep Jul 26 '11 at 13:14
  • @arnep, thank you! I've successfully created metod Station::distance_to, and it counts distance. But problem is code for sorting doesn't work, there's no errors but items are unsorted. I tried to use `sort!` but it gives me nomethod error. – lich Jul 27 '11 at 12:53
  • @lich did you use `sort` or `sort_by`? (Btw: `sort!` does not exist as it would change the object itself, but enumerables are unordered, so this is not possible.) What does `Station#distance_to` return? A numerical value? – arnep Jul 27 '11 at 13:45
  • Now it is: `sort_by { |c| @station.distance_to(c)[:value]}`. :value returns integer. It was a problem with that, but now it always returns integer value. – lich Jul 28 '11 at 07:16
  • @arnep do you have any suggestions? – lich Jul 29 '11 at 09:12
  • @arnep Thank you for your help, but this code `sort_by { |c| @station.distance_to(c)[:value]}` doesn't perform any sort actions – lich Jul 29 '11 at 09:20
  • @lich There seems another issue ... if `sort_by` gets anything that is comparable using `<=>` it will return the ordered objects. – arnep Jul 29 '11 at 11:18
  • @arnep oh, stupid me! In `distance_to(c)` `c` is a wrong argument, i should pass `c.address`. Now it all works. thank you again :) – lich Jul 29 '11 at 12:01
  • @arnep, a little offtopic. What is a best way to cache such results from Google Directions in database? How to do this? – lich Sep 07 '11 at 08:56
  • @lich My idea would be to use a table with columns `station`, `atm`, `distance`. So you can do queries like `SELECT atm, distance FROM cached_distances WHERE station = "foo" ORDER BY distance` to get the nearest ATMs. If you query for a station and get an empty resultset from your database, you do a fallback to the Google API, fetch all results and put them into the database. – arnep Sep 07 '11 at 12:03