在一个ERB块中渲染多个表达式的输出

时间:2015-06-28 05:26:08

标签: ruby-on-rails ruby ruby-on-rails-4 erb helper

我有一个看起来像这样的帮手:

override func viewDidLoad() {
    super.viewDidLoad()

    let button = UIButton(frame: CGRect(x: 0, y: 0, width: 80, height: 30))
    button.hidden = true
    button.backgroundColor = UIColor.redColor()

    self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    let view = self.navigationItem.rightBarButtonItem?.customView
    view?.hidden = false
    view?.alpha = 0
    UIView.animateWithDuration(0.4, animations: { () -> Void in
        view?.alpha = 1.0
    })
}

我需要渲染所有链接及其嵌套的if current_user.find_voted_items(vote_scope: :inspired).include?(post) link_to vote_inspired_post_path(post, vote_scope: :inspired), method: :post, data: { confirm: 'Are you sure this post Inspires you?' }, class: "btn btn-default" do "<i class='fa fa-lightbulb-o'></i> <br />Inspired".html_safe end link_to vote_happy_post_path(post, vote_scope: :happy), method: :post, data: { confirm: 'Are you sure this post makes you happy?' }, class: "btn btn-success" do "<i class='fa fa-smile-o'></i> <br />Happy".html_safe end link_to vote_disappointed_post_path(post, vote_scope: :disappointed), method: :post, data: { confirm: 'Are you sure this post disappointed you?' }, class: "btn btn-info" do "<i class='fa fa-meh-o'></i> <br />Disappointed".html_safe end link_to vote_upset_post_path(post, vote_scope: :upset), method: :post, data: { confirm: 'Are you sure this post upsets you?' }, class: "btn btn-inverse" do "<i class='fa fa-frown-o'></i> <br />Upset".html_safe end end 标记 - 但由于某种原因,此版本只是渲染最后一行。

所有这些都在名为<i>的方法中,在视图中就像这样调用:show_vote_buttons(post)

解决这个问题的最佳方法是什么?

4 个答案:

答案 0 :(得分:5)

基本上,这背后的原因是<%= %>呈现show_vote_buttons方法的输出。此方法没有显式返回任何内容,因此在您的情况下,返回最后一个计算的表达式,即最后link_to个输出。

在一般情况下,如果您没有使用辅助方法并且仅使用多个link_to调用粘贴它的正文,您将获得相同的行为。原因类似:<%= %>不呈现每个link_to,它在<%= %>内执行代码,然后输出最后一次计算表达式的结果。

我看到两种不同的方法来改变输出:

  1. 辅助方法:连接所有已计算表达式的输出并打印为一个字符串:
    1.1在每个<<周围使用()和括号link_to;
    1.2创建带双引号"的字符串,并在其中插入link_to#{}输出;
    1.3使用concat;
  2. 部分观点:从现有的帮助方法构建单独的视图,并使用<%= %>输出每个link_to
  3. P.S。在测试了所有四种方法之后,我得出结论(这是个人意见),第二种方法更为可取,至少因为它在视图中保持渲染并避免可能看起来混乱的连接。例如,在Devise gem中使用了类似的方法,其中所有共享链接都位于app/views/devise/shared/_links.html.erb 部分。

答案 1 :(得分:1)

  

但由于某种原因,这个版本只是渲染最后一行。

这是因为在Ruby中,如果方法没有显式return,则方法的返回值是在方法退出之前执行的最后一行的值。如果您想从方法中返回多个值,请使用return关键字并使用逗号分隔您的值。

#will return an array [1,2,3]
def some_method
 return 1,2,3
end

此外,我同意其他答案,即您的代码应该更干,但我只是想澄清您的原始问题。

答案 2 :(得分:0)

@suslov围绕这个答案完美地解释了这个原因。元编程可能会使代码保持DRY:

DATA = {
  inspired: { ico: 'fa-lightbulb-o', 
              msg: 'Are you sure this post Inspires you?',
              btn: 'btn-default' },
  happy: {    ico: 'fa-smile-o', 
              msg: 'Are you sure this post makes you happy?',
              btn: 'btn-success' },
  ... }

if current_user.find_voted_items(vote_scope: :inspired).include?(post)
  DATA.map do |k, v|
   instance_eval %Q{
     link_to vote_#{k}_post_path(post, vote_scope: :#{k}), 
               method: :post, 
               data: { confirm: #{v[:msg]} }, 
               class: "btn #{v[:btn]}" do
       "<i class='fa #{v[:ico]'></i> <br />#{k.capitalize}".html_safe
     end
   }.join($/) # return them all, concatenated with separator
  end
end

答案 3 :(得分:0)

尝试使用此代码

if current_user.find_voted_items(vote_scope: :inspired).include?(post)
concat(link_to vote_inspired_post_path(post, vote_scope: :inspired), method: :post, data: { confirm: 'Are you sure this post Inspires you?' }, class: "btn btn-default" do
  safe_concat(content_tag(:i, "Inspired", calss: "fa fa-lightbulb-o"))
end)
concat(link_to vote_happy_post_path(post, vote_scope: :happy), method: :post, data: { confirm: 'Are you sure this post makes you happy?' }, class: "btn btn-success" do
  safe_concat(content_tag(:i, "Happy", calss: "fa fa-smile-o"))
end)
concat(link_to vote_disappointed_post_path(post, vote_scope: :disappointed), method: :post, data: { confirm: 'Are you sure this post disappointed you?' }, class: "btn btn-info" do
  safe_concat(content_tag(:i, "Disappointed", calss: "fa fa-meh-o"))
end)
concat(link_to vote_upset_post_path(post, vote_scope: :upset), method: :post, data: { confirm: 'Are you sure this post upsets you?' }, class: "btn btn-inverse" do
  safe_concat(content_tag(:i, "Upset", calss: "fa fa-frown-o"))
end)
end

注意: 未经过测试。