Fixing no route matches for previous/next inbox function

I am stuck on my previous/next functions for the inbox messaging. For starters on certain messages I am getting a “no route matches” error. And then in addition to that problem the previous/next links are skipping messages. It should go in order, as in if you’re on message 8. The previous link should be 7, and the next link should point to 9. I have been at work on this for quite some time and can’t quite get it to work.

message model:


class Message < ActiveRecord::Base
	attr_accessible :subject, :body, :sender_id, :recipient_id, :read_at,:sender_deleted,:recipient_deleted
	validates_presence_of :subject, :message => "Please enter message title"

	belongs_to :sender,
	:class_name => 'User',
	:foreign_key => 'sender_id'
	belongs_to :recipient,
	:class_name => 'User',
	:foreign_key => 'recipient_id'

    # marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.
    # When both sender and recipient marks it deleted, it is destroyed.
    def mark_message_deleted(id,user_id)
         self.sender_deleted = true if self.sender_id == user_id
         self.recipient_deleted = true if self.recipient_id == user_id
         (self.sender_deleted && self.recipient_deleted) ? self.destroy : self.save!
     end
    # Read message and if it is read by recipient then mark it is read
    def readingmessage
      self.read_at ||= Time.now
      save
    end

    # Based on if a message has been read by it's recipient returns true or false.
    def read?
    	self.read_at.nil? ? false : true
    end

    def self.received_by(user)
       where(:recipient_id => user.id)
     end

     def self.not_recipient_deleted
       where("recipient_deleted = ?", false)
     end

     def self.sent_by(user)
        Message.where(:sender_id => user.id)
      end

      def previous(same_recipient = true)
        collection = Message.where('id <> ? AND updated_at > ?', self.id, self.updated_at).order('updated_at ASC')
        collection.where(recipient_id: self.recipient_id) if same_recipient
        collection.first
      end

      def next(same_recipient = true)
        collection = Message.where('id <> ? AND updated_at < ?', self.id, self.updated_at).order('updated_at DESC')
        collection.where(recipient_id: self.recipient_id) if same_recipient
        collection.first
      end
    end

Messages controller




class MessagesController < ApplicationController

  before_filter :set_user

  def index
    if params[:mailbox] == "sent"
      @messages = @user.sent_messages
    elsif params[:mailbox] == "inbox"
      @messages = @user.received_messages
    #elsif params[:mailbox] == "archieved"
     # @messages = @user.archived_messages
    end
    if params[:mailbox] == "unread"
    @messages = @user.unread_messages
  end
  end

  def new
    @message = Message.new
    if params[:reply_to]
      @reply_to = User.find_by_user_id(params[:reply_to])
      unless @reply_to.nil?
        @message.recipient_id = @reply_to.user_id
      end
    end
  end

  def create
    @message = Message.new(params[:message])
    @message.sender_id = @user.id
    if @message.save
      flash[:notice] = "Message has been sent"
      redirect_to user_messages_path(current_user, :mailbox=>:inbox)
    else
      render :action => :new
    end
  end

  def show
     @message = Message.find(params[:id])
     @message.readingmessage if @message.recipient == current_user
   end

   def destroy
     @message = Message.find(params[:id])
     @message.destroy
     flash[:notice] = "Successfully deleted message."
     redirect_to user_messages_path(@user, @messages)
   end

  def delete_multiple
      if params[:delete]
        params[:delete].each { |id|
          @message = Message.find(id)
          @message.mark_message_deleted(@message.id,@user.id) unless @message.nil?
        }
        flash[:notice] = "Messages deleted"
      end
      redirect_to user_messages_path(@user, @messages)
  end

  private
    def set_user
      @user = current_user
    end
end

show.html



	 <%= link_to 'Next', user_message_path(current_user, @message.next) %>
	  <%= link_to 'Previous', user_message_path(current_user, @message.previous) %>

error message



No route matches {:action=>"show", :controller=>"messages", :user_id=>#<User id: 1, email: "admin@admin.com", password_digest: "$2a$10$dAakIwpw/FLroM3Khkm6luEb8yDJLzCxVzLTKeS7bFg8...", zip_code: "39484", birthday: "1984", name: nil, username: "admin", gender: "women", ethnicity: "1", sexuality: nil, career: "Websites", education: "5", religion: "1", politics: nil, children: "2", height: nil, user_smoke: "3", user_drink: "1", about_me: "i am the admin!", inches: "2", feet: "6", created_at: "2013-04-17 13:31:11", updated_at: "2013-05-08 17:28:08", auth_token: "LTzif2q6921TM4pQzfmEGg", password_reset_token: nil, password_reset_sent_at: nil, admin: nil, role: "admin", roles_mask: nil, age: "39", age_end: nil>, :id=>nil}

The “no route matches” error is when next or previous are returning nil so the routes can’t be generated without an id.

Perhaps the simplest fix is to wrap conditionals around those links.


<% if @message.next.present? %>
  <%= link_to 'Next', user_message_path(current_user, @message.next) %>
<% end %>
<% if @message.previous.present? %>
  <%= link_to 'Previous', user_message_path(current_user, @message.previous) %>
<% end %>

Not sure what same_recipient is being used for but these look ok to me.

def previous
  Message.order('updated_at DESC').where('updated_at < ?', updated_at).last
end
def next
  Message.order('updated_at DESC').where('updated_at > ?', updated_at).first
end

The id’s won’t be next/previous as you’re not ordering by id, you’re ordering by the updated_at

Sorry for delayed response, was on vacation but now I’m back to working full-time on this project. Thanks for the assistance!

I forgot I had it with updated it, as oppose to created at. So I switch that. But I think I’m going to try the id number instead as that would be much easier. As I think the created time goes by when the user clicks on “new message”, which in some cases users will go to new message and just stay on that page while they’re browsing some other page from the internet. So to get a true next/previous I probably should sort by ID. I will see what I can do about that.

Why did the conditionals have to be wrap about it? I just want to understand the code so I know for the future.