【问题标题】:How to set different variable in a rails partial based on a condition?如何根据条件在rails部分中设置不同的变量?
【发布时间】:2014-02-14 22:24:27
【问题描述】:

我需要能够根据从数据库中评估同一个表的条件从数据库中提取不同的值,即为多个条件呈现一个部分?例如,在我的索引视图中,我有:

- @places.each 做 |place| - 如果 place.level == 1 = 渲染“地点”,一:地点 - elsif place.level == 2 = 渲染“地点”,二:地点 - 别的 = 渲染“地点”,无:地点

这是我的部分:

%table.table %标题 %h2=地点名称 %thead %t 正文 %tr %td 姓名: %td = place.place_name %tr %td 房间总数: %td = place.places_rooms %tr %td 总名额: %td = place.places_count

我的部分索引页代码应该是什么样的?

非常感谢!

【问题讨论】:

  • 你能澄清你的问题吗?根据您提供的信息,尚不清楚place.level 应该产生什么影响。
  • 因此,如果 place.level 值为 1,则部分将根据该级别从数据库中提取不同的数据。希望这是有道理的?

标签: ruby-on-rails ruby-on-rails-3


【解决方案1】:

你试图以不同的方式渲染什么条件?

我问是因为您将 place 作为本地人传递,但您指定一、二和无作为本地人,但它们不存在于您的局部。如果没有更多信息,我唯一的猜测是你应该这样做= render 'place', place: place

根据需求进行编辑:

-@places.each do |place|
  = render 'place, place: place

部分

%table.table
  %caption
    %h2= place.name
  %thead
  %tbody
    %tr
      %td
        Name:
      %td
        = place.try(:"level_#{place.level}_place") || place.place_name
    %tr
      %td
        Total rooms:
      %td
        = place.places_rooms
    %tr
      %td
        Total places:
      %td
        = place.places_count 

所以我认为这将是做到这一点的方式。但也许这应该向您暗示您的表可能包含许多不必要的字段。也许最好创建一个级别表,然后在它们之间创建一个关系。

【讨论】:

  • 好问题肖恩。因此,我的位置表中有一个级别,即一、二等,基于此级别,我想渲染部分。不过,我不知道该怎么做。我纠结的是如何在部分中设置变量一、二等?希望我说得通吗?谢谢。
  • 确实有道理。但是你想在局部渲染这个关卡吗?否则我会在你的控制器中将@places 实例变量重置为@places = Place.where(level: 1)。显然,您可以使用 params[:level] 代替 1 或类似的东西,具体取决于您要实现的目标。
  • 是的,肖恩。里面的部分是理想的。
  • 类似这样的东西,但这不起作用。 =render partial: 'place', locals: {levels: [place.level, place.level > 0 ? 2 : nil]}。我的索引应该是什么样子的?
  • 我试图做我认为你正在努力实现的目标,但我仍然不完全确定。您尝试在部分内部的哪个位置添加关卡数据?还是首先渲染部分的条件是水平?
【解决方案2】:

视图层中的逻辑是一种反模式,因为它使视图的可读性降低/与领域语言的关联性降低。

您是否考虑过将您的@places 包装在您自己创建的decorator object 中?假设我正确理解了这个问题(免责声明:不是 100% 肯定我这样做了),我可能会这样做:

假设你的控制器是PlacesController...

# app/controllers/places_controller.rb

class PlacesController < ApplicationController
  def index
    @places = PlaceWithLevels.decorate(places)
  end

  private

  def places
    Place.all
  end
end

现在我们定义装饰器对象PlaceWithLevels(根据您的域,您可能会想出一个更好的名称):

# app/models/place_with_levels.rb

class PlaceWithLevels < SimpleDelegator
  def self.decorate(places)
    places.map do |place|
      self.new(place)
    end
  end

  # not sure what to name this since I'm not sure what you're
  # trying to accomplish, but note that this is the method we'll
  # be calling in the partial
  def foo
    case levels
    when 0; 'Text you want to show up when there are 0 levels'
    when 1; 'Text you want to show up when there is 1 level'
    when 2; 'Text you want to show up when there are 2 levels'
  end
end

那么,在视图中:

# app/views/places/index.html.haml
= render @places

请注意,我们不需要调用@places.each,因为render 将对集合的每个成员调用#to_partial_path,以确定要渲染的部分。 最后,在部分(由于我们使用上面的SimpleDelegator,对places_rooms等的方法调用将在这里工作):

# app/views/places/_place.html.haml
%table.table
  %caption
    %h2= place.name
  %thead
  %tbody
    %tr
      %td
        Name:
      %td
        = place.foo
    %tr
      %td
        Total rooms:
      %td
        = place.places_rooms
    %tr
      %td
        Total places:
      %td
        = place.places_count

请注意,我们这里不再需要特殊的逻辑...只需在我们的装饰器对象上调用name 方法(或任何适当的方法),但从视图的角度来看,视图不需要要知道它可以与 place 以外的任何东西一起使用。

如果您需要根据level 属性呈现完全不同的部分,此技术也非常有用 — 只需在装饰器对象上定义您自己的 to_partial_path 方法,例如:

def to_partial_path
  case level
  when 0; 'zero_level_place'
  when 1; 'single_level_place'
  when 2; 'two_level_place'
end

希望这有帮助!!!!

PS:我也鼓励你去掉places_roomsplaces_count等上的places_前缀...更好的信噪比。

【讨论】:

  • 谢谢安东尼。这听起来是一个非常好的主意。我还没有尝试过,但我会在下一个项目中尝试。
猜你喜欢
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 1970-01-01
相关资源
最近更新 更多