Finding the next item, in a group of items

Hi,

Basically I currently have this system where there are categories, and
tutorials; obviously categories have many tutorials, and every
tutorial must belong_to a category.

The tutorials are then displayed in order of there id (auto-
incrementing) in their categories show method.
The thing is, I want to create a link that goes from one tutorial
(with an id of 10 for example) to the next tutorial in that category
(which might not have an id of 11, as I create different tutorials at
different times, therefore creating different ids for two tutorials
seemingly next to eachother in order).

Obviously I know I will need something like this:
<%= link_to ‘Next lesson…’, %>

but I just don’t know how I can manage it…

By the way, every tutorial has a: category_id to determain which
category they are in (this is an integer).

Please Help,

Thanks In Advance,

Joe

On May 2, 1:29 pm, Joe [email protected] wrote:

<%= link_to ‘Next lesson…’, %>

but I just don’t know how I can manage it…

By the way, every tutorial has a: category_id to determain which
category they are in (this is an integer).

If I were you, i’d create a position column on tutorials, which
determines the ordering of tutorials for a category (ordering by id
might seem the simplest but stops you from ever reordering tutorials.
Given a tutorial, the next one is the first one in the same category
whose position is greater than the current ones (you could write a
next_tutorial method on tutorial). There’s a plugin called
acts_as_list that you might find helpful maintaining the position
column. If you’re hell bent on ordering by id then it’s as if id is
your position column

Fred

whose position is greater than the current ones (you could write a
next_tutorial method on tutorial). There’s a plugin called
acts_as_list that you might find helpful maintaining the position
column. If you’re hell bent on ordering by id then it’s as if id is
your position column

Fred

I agree with Fred as it allows you to easily re-order the tutorials if
you want to, but if you don’t… then…

next_tutorial = Tutorial.find(:conditions => [“id > ? AND category_id
= ?”, current_tutorial_id, current_category_id], :order =>
‘id’, :limit => 1)

prev_tutorial = Tutorial.find(:conditions => [“id < ? AND category_id
= ?”, current_tutorial_id, current_category_id], :order => ‘id
DESC’, :limit => 1)

Ok, so I’ve created my position thing for every tutorial. However now
I need to know how I can setup render :partial to order the tutorials
using the position, and then if two (or more) tutorials have the same
position, then go back and check there id, and order the ones with the
same position by id.

This is how I’m currently displaying the tutorials:

<%= render :partial => @category.tutorials %>

Does anyone have any ideas how I can adapt this?

Thanks In Advance,

Joe

Ok, So it seems that this whole tutorial ordering thing seems to be
the best way to go (thanks to philip anyway for giving me the code to
do it with ids if I wanted to);
The problem is I’m really a complete noob in RoR. I know how to create
migrations, however creating a “position” variable i which they were
independent to the category the tutorials were in; I have absolutely
no idea how to do that. And you talk about writing methods, I also do
not know where these methods would be created (inside a controller
perhaps?).

Any help with this task would be kindly appriciated,

Thanks In Advance,

Joe

So I change it to this: <%= render :partial =>
@category.tutorials.ordered_by_position %>
and I get the error: undefined method `ordered_by_position’

I’m guessing that’s because I have to create a method that orders them
by position. However I’m a noob in ruby on rails, where do I create
the method, and how do I make it order them by position?

Thanks in advance,

Sorry for being such a noob,

Joe

On May 3, 10:35 am, Frederick C. [email protected]

Anyone?

Any help would be much appriciated,

Thanks In Advance,

Joe

Anyone?

Any help would be much appriciated,

Thanks In Advance,

Joe

On May 3, 8:12 am, Joe [email protected] wrote:

Does anyone have any ideas how I can adapt this?

I’d probably create a named_scope on Tutorial which ordered things by
position. Since named_scopes can be chained with each other and with
an association you could do @category.tutorials.ordered_by_position

Fred

Just to confirm the above IS me asking for more help; and I didn’t
mean to post 3 times, I think it glitched a bit.

Please Help,

Thanks In Advance,

Joe

Thanks for your help, but I’m not sure where classes go.

I’ve tried copying this code into the tutorials_controller:

def self.ordered_by_position
find :all, :order => ‘position’
end

But it still has this error: undefined method `ordered_by_position’

I assume this is because I have either put this code in the wrong
place; of need to put it in a different place WITH this bit: class
Tutorial < AR::Base (and of course the extra end)…

I’m really sorry for being such a pain,

Thanks In Advance,

Joe

On 6 May 2010 15:46, Joe [email protected] wrote:

I’ve tried copying this code into the tutorials_controller:

def self.ordered_by_position
find :all, :order => ‘position’
end

If you’re calling “Tutorial.ordered_by_position” that code needs to be
in the Tutorial model, not in a controller…

Thanks so much! It works!

However now I’m just trying to get the whole ‘next lesson’ thing
working.

I’ve tried it using this code in the model:

def self.next_lesson
find :all, :conditions => [“position > ? AND category_id = ?”,
@tutorial_id, @category_id], :order => ‘position’, :limit => 1
end

and then this code in the link:

<%= link_to ‘Next lesson.’, @tutorial.next_lesson %>

However I get this error:

undefined method `next_lesson’

Why is this happening? and how do I overcome it?

Thanks for your help,

Joe

On 6 May 2010 16:41, Joe [email protected] wrote:

def self.next_lesson
find :all, :conditions => [“position > ? AND category_id = ?”,
@tutorial_id, @category_id], :order => ‘position’, :limit => 1
end

and then this code in the link:

<%= link_to ‘Next lesson.’, @tutorial.next_lesson %>

using “self” in the method name makes it a class method; so accessible
with “Tutorial.next_lesson”. But you’d have to pass in the tutorial_id
and category_id.

Seriously - someone much earlier suggested using acts_as_list. Do. It
deals with all of this for you…

On May 3, 11:28 am, Joe [email protected] wrote:

So I change it to this: <%= render :partial =>
@category.tutorials.ordered_by_position %>
and I get the error: undefined method `ordered_by_position’

I’m guessing that’s because I have to create a method that orders them
by position. However I’m a noob in ruby on rails, where do I create
the method, and how do I make it order them by position?

Well a trick here is that if you make a class method on Tutorial then
you can call it on a tutorials association and will work just fine,
and any finds and so on are scoped to the association. So you could
write

class Tutorial < AR::Base
def self.ordered_by_position
find :all, :order => ‘position’
end
end

A better choice for this sort of thing is named_scope. They are more
flexible and more reusable. Have a look at the docs for those.

Fred

When I change it to “Tutorial.next_lesson” it then says: undefined
method `nil_class_path’

Is this because I have to “pass in the tutorial_id and category_id” or
is it a different problem?

As for acts_as_list, I would prefer not to use it for now and just
keep with using position; However it is something I will be looking at
for future projects…

Please Help,

Sorry for being such a pain,

Thanks In Advance,

Joe

On 6 May 2010 17:23, Joe [email protected] wrote:

As for acts_as_list, I would prefer not to use it for now and just
keep with using position; However it is something I will be looking at
for future projects…

Why?! acts_as_list uses the position column itself. You can scope it
(so you can have a list per category, or whatever) and it gives you
the next/previous item methods:

http://api.rubyonrails.org/classes/ActiveRecord/Acts/List/InstanceMethods.html

As it is, you’re trying to reinvent the wheel.

On May 6, 5:23 pm, Joe [email protected] wrote:

When I change it to “Tutorial.next_lesson” it then says: undefined
method `nil_class_path’

Is this because I have to “pass in the tutorial_id and category_id” or
is it a different problem?

You’re probably getting nil_class_path because you are returning nil
from somewhere.
You definitely need to pass in the values of tutorial_id - that class
method isn’t going to be stealing instance variables out of the
controller or anything like that.
Personally I’d have next_lesson be an instance method of tutorial

link_to ‘Next’, @tutorial.next_lesson

sounds nicer than

link_to ‘Next’, Tutorial.next_lesson(@tutorial.id,
@tutorial.category_id)

or anything like that.

Fred

I did try using: “@tutorial.next_lesson” before, however I got this
error so figured it must be wrong: undefined method `next_lesson’

I don’t quite know why it can’t find the method since it’s obviously
in the model…

Has anyone got a solution for this?

Thanks In Advance,

Joe

On May 6, 5:30 pm, Frederick C. [email protected]

Please note I’ve also tried this: Tutorial.next_lesson(@tutorial.id,
@tutorial.category_id)

Which results in some compile errors: wrong number of arguments (2 for
0)

I guess this is because my model doesn’t take any parameters, and I’m
giving it 2…

I’ll be looking around for how I can make it accept 2 parameters (or
fix the previous error) but it would be nice if someone could help
out,

Thanks In Advance,

Joe