开发者

link_to_unless problem

I have this RoR snippet in a view:

<%= link_to_unless(@posts_pages[:previous].nil?, 
  "Previous", 
  blog_with_page_path(:page_num => @posts_pages[:previous])) %>

Here blog_with_page is a named route. The snippet works if @posts_pages[:previous].nil? is false (as expected) and the link is generated correctly. However, when @posts_pages[:previous].nil? is true, instead of simply getting the "Previous" string back, I get an error telling me that the route couldn't be generated using :page_num=>nil. Is this the expected behavior? If the condition is met, the route code shouldn't be evaluated, should it? Here's the complete error: blog_with_page_url failed to generate from {:page_num=>nil, :action=>"show", :controller=>"pages"}, expected: {:action=>"show", :controller=>"pages"}, diff: {:page_num=>nil}

I've been looking at the link_to_unless code and I don't understand why I get the error since it should be returning simply the name开发者_高级运维:

# File actionpack/lib/action_view/helpers/url_helper.rb, line 394
  def link_to_unless(condition, name, options = {}, html_options = {}, &block)
    if condition
      if block_given?
        block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
      else
        name
      end
    else
      link_to(name, options, html_options)
    end
  end

I'm using Rails 2.3.11 and Ruby 1.8.7

Cheers!


Because Ruby is not a lazy language, blog_with_page_path(:page_num => @posts_pages[:previous]) gets evaluated as soon as you call it, regardless of whether the value ever gets used by link_to_unless.


Given the various other answers which explain your problem, why not try this as your solution:

link_to( "Previous", blog_with_page_path(:page_num => @posts_pages[:previous]) ) unless @posts_pages[:previous].nil?

This will evaluate the "unless" condition first, sparing you the bogus link_to when @post_pages[:previous] is nil.

-- EDIT --

As pointed out in the comment, since you need the string back maybe the simplest way is just a ternary:

@posts_pages[:previous].nil? ? "Previous" : link_to( "Previous", blog_with_page_path(:page_num => @posts_pages[:previous]) )


It looks like a bug. This code is not "lazy" so it executes all statements. So you can go three ways:

  1. Patch it
  2. Make simple if .. else
  3. Hack it:

Like this

<%= link_to_unless(@posts_pages[:previous].nil?, 
  "Previous", 
  blog_with_page_path(:page_num => @posts_pages[:previous] || 0)) %>

Instead of 0 you can set any number, it will never be setted


Function arguments are always evaluated before the function runs, whether or not they are needed:

ree-1.8.7-2011.03 :005 > def print_unless(condition, thing_to_print)
ree-1.8.7-2011.03 :006?>   puts "I started executing"
ree-1.8.7-2011.03 :007?>   puts thing_to_print unless condition
ree-1.8.7-2011.03 :008?>   end
 => nil 
ree-1.8.7-2011.03 :009 > print_unless(true, 1/0)
ZeroDivisionError: divided by 0
    from (irb):9:in `/'
    from (irb):9
    from :0
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜