views:

335

answers:

2

Hello,

does anyone know how to prevent the failing mechanism of link_to_unless_current?

f.e.: I have my page navigation with

link_to_unless_current "new task", new_task_path

When I click on the link, i come to the new taks path form... And no link is created -> ok. Then I put incorrect values in the form and submit.

The TasksController processes the "create" action, the validation for the ActiveRecord-model fails because of the incorrect data and the controller renders the "new" action (and includes the error messages for the model).

class TasksController < ApplicationController
    def create
        @task = Task.new(params[:task])

        if @task.save
            flash[:notice] = 'task was successfully created.'
            redirect_to(tasks_url)
          else
            render :action => "new"
        end
    end
end

But here the link gets created! -> Because of the difference between the urls:

  link path = new_task_path

but

  posted path = tasks_path with :method => :post

Does anybody know how to cleanly solve this problem?

Thanks

A: 

You can do it with link_to_unless instead of link_to_unless_current:

link_to_unless(controller_name == 'tasks' && 
                 (action_name == 'new' || action_name == 'create'), 
               new_task_path)
Shadwell
Lol... easy easy easy gg
Lichtamberg
But isn't there a solution that works with named routes?
Lichtamberg
+1  A: 

Having a quick look at the source for link_to_unless_current...

...it makes use of current_path? such that you should be able to do something like this:

In a helper...

def current_page_in?(*pages)
  pages.select {|page| current_page?(page)}.compact.any? 
end

... and then in your view, you can just supply an array of either named_routes or hashes like Shadwell's answer above.

<%= link_to_unless(current_page_in?(new_thing_path, things_path), "add a thing") %>

You get the idea...

UPDATED

Had a think about this... and it'd be great if you could just use it like you'd hoped that the original method worked. Here we compare the supplied named route (or controller + action hash) with the current page AND its referrer.

def current_page_or_referrer_in(options)
  url_string = CGI.unescapeHTML(url_for(options))
  request = @controller.request
  # We ignore any extra parameters in the request_uri if the
  # submitted url doesn't have any either.  This lets the function
  # work with things like ?order=asc
  if url_string.index("?")
    request_uri = request.request_uri
    referrer_uri = request.referrer
  else
    request_uri = request.request_uri.split('?').first
    referrer_uri = request.referrer.split('?').first
  end

  #referrer_uri always has full path (protocol, host, port) so we need to be sure to compare apples w apples
  if url_string =~ /^\w+:\/\//
    ["#{request.protocol}#{request.host_with_port}#{request_uri}", referrer_uri].include?(url_string)
  else
    referrer_uri = referrer_uri.gsub(request.protocol, '').gsub(request.host_with_port, '')
    [request_uri, referrer_uri].include?(url_string)
  end
end

The beauty is that it now lets you just do this (from your example):

<%= link_to_unless(current_page_or_referrer_in(new_task_path), "Add a task") %>

It'll then display if you're on new_task_path OR a page to which it has been sent (such as the create page

mylescarrick
Cool cool cool thanks
Lichtamberg
Almost like a good answer! But the problem now goes to the other side:I have both the new and list (i.e. index) link put at the left nav bar which I want to have a current highlight on the action I am in. This particular problem makes it not possible to find the true active link it should highlight (i.e. new) because the post url means the index link would be highlighted as well. Really looks ugly in this part....
goodwill