如何在HAML中使用if/else语句而不重复缩进的代码

16
根据用户是否已登录,我想打印不同种类的%body标记。
这是我目前的做法:
- if defined? @user
  %body(data-account="#{@user.account}")
    %h1 Welcome
    -# all my content
- else
  %body
    %h1 Welcome
    -# all my content

正如您所看到的,其中有很多重复的代码。我该如何消除这些重复呢?我已经尝试了以下方法:

- if defined? @user
  %body(data-account="#{@user.account}")
- else
  %body
  %h1 Welcome
  -# all my content

很遗憾,这并不起作用,因为HAML将其解释为%h1和内容是else语句的一部分,当然它们并不是。

有什么解决办法吗?我经常遇到这个问题,所以我无法想象没有一个简单的解决办法。


第二个 %body 应该放在 else 内部还是外部? - Paul Hoffer
是的,应该这样。但是 %h1 和内容不应该改变。 - Marc
6个回答

13

因为 HAML 自动分配“end”语句的方式,我认为您无法避免缩进问题,但是您可以将 if 语句推入 body 标记本身中 -

%body{:data_account => (defined? @user ? @user.account : nil)}

相对于

%body(data-account="#{@user.account}")

不是超级漂亮,但比重复整个块要好看一些!


1
我无法想象HAML能够为这种常见用例提供优雅的解决方案。如果真是这样,我可能不得不考虑重新使用普通的HTML。无论如何,感谢您的建议。如果@user没有定义,是否可以完全省略"data-account"属性? - Marc
这段代码将会实现这个功能 - 设置:data_account => nil (间接地)将导致HAML忽略该属性并生成一个普通的body标签。 - bhaibel
代码返回以下内容:<body data-account='expression'> 因此,它不执行表达式并返回其值,而是仅显示单词“expression”。(不,@user.account!= 'expression') - Marc
结果是使用括号定义?方法可以解决问题。 - Marc

12
!!!
 - @user = "jed" #=> stubbing out an instance
%html
  %head
    - string = defined?(@user) ? "#{@user}" : nil #=> for demo only, wrap this in a helper method
    %title{'data-account' => string}
  %body
    =yield

Marc - 在我发布这个回答之前没有看到@bahabil的回答,他的回答也可以工作,或者你问到当@user.nil?时不设置data-account属性,这将做到这一点,它只是不会在字符串为nil时放入键。字符串可以是视图助手中的帮助方法调用。 - Jed Schneider
谢谢,非常好用!定义?-方法的括号实际上解决了我在bhaibel答案中遇到的问题。 - Marc
我可以在哪里定义辅助方法? - Lokesh
1
在应用程序助手或控制器的相关助手中使用@Lokesh:http://mixandgo.com/blog/the-beginner-s-guide-to-rails-helpers - Jed Schneider

4
HAML的优雅解决方案是helpers。
class ApplicationHelper...

  def body_for_user(user, &blk)
    return content_tag(:body, :'data-account' => user.account, &blk) if user
    content_tag(:body, &blk)
  end

end

上述三元运算符对于这种特定情况已经足够了,但对于更复杂的事情,请使用辅助函数。
要使用它,在您的视图中将%body(...)更改为= body_for_user @user do

我在开头的帖子中没有明确提到,但我并没有使用Rails而是使用Sinatra,它没有content_tag方法。我可能可以模仿它,但我更愿意保持尽可能简单。不过还是感谢你的建议,在我的Rails项目中会很有用。 - Marc

1

对于任何想要解决HAML中Ruby if/else问题的人,这是我解决它的方法:

%tr{ id: (line_item == @current_item) ? "current_item" : nil }
  %td= button_to '-', decrement_line_item_path(line_item), method: :put, remote: true
  %td #{line_item.quantity}&times;
  %td= line_item.product.title
  %td.item_price= number_to_currency(line_item.total_price)

1
编写一个类似这样的帮助程序:
def body_attributes
  {}.tap do |hash|
    hash[:data] = {}
    hash[:data][:account] = @user.account if @user
    # add any other attributes for the body tag here
  end
end

然后从body元素调用helper:

%body{ body_attributes }
  %h1 Welcome
  -# all my content

请参阅http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#attribute_methods,了解有关属性方法的更多信息。 - Jeremy Weiskotten
我可能做错了什么,但这只返回:<body body_attributes> - Marc
更新的例子。您需要在方法名称周围加上花括号(我使用了圆括号)。 - Jeremy Weiskotten

0

我通常在控制器中设置@@menu变量,然后在启用引导布局的layout.haml中定义:

  ...
  %body
    .navbar.navbar-fixed-top
      .navbar-inner
        .container
          %a.btn.btn-navbar{"data-target" => ".nav-collapse", "data-toggle" => "collapse"}
            %span.icon-bar
            %span.icon-bar
            %span.icon-bar
          %a.brand{:href => "/"} AwesomeApp
          .nav-collapse
            %ul.nav
              %li{:class => @@menu == 'home' && :active}
                %a{:href => "/"} Home
              %li{:class => @@menu == 'about' && :active}
                %a{:href => "/about"} About
              %li{:class => @@menu == 'contact' && :active}
                %a{:href => "/contact"} Contact

当我将@@menu设置为'about'时,它会呈现:
  <body>
    <div class='navbar navbar-fixed-top'>
      <div class='navbar-inner'>
        <div class='container'>
          <a class='btn btn-navbar' data-target='.nav-collapse' data-toggle='collapse'>
            <span class='icon-bar'></span>
            <span class='icon-bar'></span>
            <span class='icon-bar'></span>
          </a>
          <a class='brand' href='/'>AwesomeApp</a>
          <div class='nav-collapse'>
            <ul class='nav'>
              <li>
                <a href='/'>Home</a>
              </li>
              <li class='active'>
                <a href='/about'>About</a>
              </li>
              <li>
                <a href='/contact'>Contact</a>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>

我没有看到应用“about”类...你确定这是在设置@@menu变量之后吗? - bbop
@v_mitchell:有一个三元运算符“@@menu == 'about' && :active”,如果@@menu等于字符串“about”,则返回:active。 - andrej

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接