Acts_as_ordered plugin and scope

Hi,

I would like to use the acts_as_ordered plugin to step through a
collection. My problem is the :scope option. I have a one-to-many
relationship between countries and cities, and I would like to step
through the cities (on a country’s page):

class City < ActiveRecord::Base

belongs_to :country
acts_as_ordered, :order => ‘name’, :scope => ‘country_id’

Now what I would like to happen is that ‘acts_as_versioned’ would
consider the last city of a given country the last object, and NOT
return the first city of the next country for city.next, but the instead
the current city. But that is not what is happening.

What do I need to do differently?

Thanks!
Ingo

Adding :wrap => false to acts_as_ordered will stop the next and previous
methods from wrapping around, that may be what you’re after.

-Jonathan.

Thanks, Jonathan!

I tried :wrap => false and it still seems to not have the desired
effect. I guess what I am looking for is a way to tell acts_as_ordered
to step through not the entire collection of records, but only the ones
that have a belong_to relationship with a specific resource. In my
example, I would like to step through not all cities, but only the
cities of one country. Basically, I am on the page
‘/countries/us/cities’ and would like to provide prev/next navigation.
Right now I am using the following options:

acts_as_ordered :scope => ‘country_id’, :order => ‘name’, :wrap => false

But acts_as_ordered still gives me cities for other countries which in
my case generates an not-found-error since I am using
@country.cities.find(params[:id]) in the controller to find the city.

Ingo

Jonathan V. wrote:

Adding :wrap => false to acts_as_ordered will stop the next and previous
methods from wrapping around, that may be what you’re after.

-Jonathan.

Try scoping to the association and not the foreign key.

acts_as_ordered :scope => :country, :order => ‘name’

When you provide a string to :scope, it should be the piece of sql used
in
the where clause of the sql. If you use a symbol it will add _id and set
a
scope of ‘country_id = #{country_id}’.

I agree it’s not the best and probably isn’t documented either.

-Jonathan.

Please send me a failing test case so I can look at this further.

-Jonathan.

Jonathan V. wrote:

Please send me a failing test case so I can look at this further.

-Jonathan.

Hi Jonathan,

below is my failing test case. It basically asserts that if I use
acts_as_ordered to step through a collection of cities that belong to a
country (:scope => :country), then all the cities I am getting should in
fact belong to that country. Maybe I’m expecting a behavior that
acts_as_ordered was not designed for? Or maybe i misunderstand what
:scope does?

Ingo

def test_next
country = Country.find(1)
city = country.cities.first
assert_equal city.country, country
(country.cities.size-1).times do
city = city.next
assert_equal city.country, country
end
end

Thanks!

I tried this and it doesn’t seem to solve the problem either.

Ingo

Jonathan V. wrote:

Try scoping to the association and not the foreign key.

acts_as_ordered :scope => :country, :order => ‘name’

When you provide a string to :scope, it should be the piece of sql used
in
the where clause of the sql. If you use a symbol it will add _id and set
a
scope of ‘country_id = #{country_id}’.

I agree it’s not the best and probably isn’t documented either.

-Jonathan.

Of course the obvious solution would be to sort both by country_id and
name, and then test whether the ‘next’ or ‘previous’ city belongs to the
correct country. But it seems counterintuitive having to test that when
you do something like germany.cities.find_by_name(‘Berlin’).next, don’t
you think?

Ingo

Ingo W. wrote:

Jonathan V. wrote:

Please send me a failing test case so I can look at this further.

-Jonathan.

Hi Jonathan,

below is my failing test case. It basically asserts that if I use
acts_as_ordered to step through a collection of cities that belong to a
country (:scope => :country), then all the cities I am getting should in
fact belong to that country. Maybe I’m expecting a behavior that
acts_as_ordered was not designed for? Or maybe i misunderstand what
:scope does?

Ingo

def test_next
country = Country.find(1)
city = country.cities.first
assert_equal city.country, country
(country.cities.size-1).times do
city = city.next
assert_equal city.country, country
end
end

hmm,

in my app this test passes only if all cities belonging to one country
happen to be in sequence. To test for this, how about something like
this:

def test_next
country_1 = Country.create(:name => ‘country 1’
country_2 = Country.create(:name => ‘country 2’
country_1.cities.create(:name => ‘city 1’)
country_2.cities.create(:name => ‘city 2’)
country_1.cities.create(:name => ‘city 3’)
country_2.cities.create(:name => ‘city 4’)

city = country_1.cities.first
assert_equal city.country, country_1
(country_1.cities.size-1).times do
  city = city.next
  assert_equal city.country, country_1
end

end

BTW I ended up taking a different route since I only need a very simple
functionality. I put the following in environment.rb:

class Array

def member_after(member)
index = self.index(member) and self[index+1]
end

def member_before(member)
index = self.index(member) and self[index-1]
end

end

Now I can do things like this:

next_city = country.cities.member_after(city)
prev_city = country.cities.member_before(city)

Ingo

Jonathan V. wrote:

That test passes with the following models:

class Country < ActiveRecord::Base
has_many :cities
end

class City < ActiveRecord::Base
belongs_to :country

acts_as_ordered :scope => :country, :order => ‘name’
end

-Jonathan.

That test passes with the following models:

class Country < ActiveRecord::Base
has_many :cities
end

class City < ActiveRecord::Base
belongs_to :country

acts_as_ordered :scope => :country, :order => ‘name’
end

-Jonathan.