【问题标题】:How to refactor a simple long case statement如何重构一个简单的长 case 语句
【发布时间】:2020-10-16 20:08:53
【问题描述】:

所以我为我的 Sinatra 项目创建了一个下拉表单,我希望它预先填充该选项。我能够做到这一点,但它变成了一个大案例陈述!任何想法如何重构这个?谢谢!

get '/animes/:id/edit' do 
    if is_logged_in?
    @anime = Anime.find_by_id(params[:id])
    case @anime.rating
    when 1
        @oneselect = "selected"
    when 2
        @twoselect = "selected"
    when 3
        @threeselect = "selected"
    when 4
        @fourselect = "selected"
    when 5
        @fiveselect = "selected"
    when 6
        @sixselect = "selected"
    when 7
        @sevenselect = "selected"
    when 8
        @eightselect = "selected"
    when 9
        @nineselect = "selected"
    when 10
        @tenselect = "selected"
    end
    erb :'animes/edit'
    else
       redirect to '/' 
    end
end 

这是我的 .erb 视图文件表单!

 <label for="rating">Rating:</label>

<select name="rating" id="rating" value="<%=@anime.rating%>">
  <option value="10"<%=@tenselect%>>10 (Masterpiece)</option>
  <option value="9"<%=@nineselect%>>9 (Great)</option>
  <option value="8"<%=@eightselect%>>8 (Very Good)</option>
  <option value="7"<%=@sevenselect%>>7 (Good)</option>
  <option value="6"<%=@sixselect%>>6 (Fine)</option>
  <option value="5"<%=@fiveselect%>>5 (Average)</option>
  <option value="4"<%=@fourselect%>>4 (Bad)</option>
  <option value="3"<%=@threeselect%>>3 (Very Bad)</option>
  <option value="2"<%=@twoselect%>>2 (Horrible)</option>
  <option value="1"<%=@oneselect%>>1 (Appalling)</option>

</select><br>

【问题讨论】:

  • 请注意以下几点:如果h = { 1=&gt;"one", 2=&gt;"two",..., 10=&gt;"ten" }@oneselect = 'cat' 然后n=1; instance_variable_set("@#{h[n]}select" , 'dog') #=&gt; "dog" 那么现在@oneselect #=&gt; "dog"。但是,我非常怀疑,如果你想要所有这些实例变量,而不是一个包含 10 元素数组的变量。

标签: ruby refactoring case sinatra erb


【解决方案1】:

抱歉,我对 Sinatra 一无所知,所以这个答案可能不符合实际。

如果我自己查看这段代码,我会考虑做类似的事情(未经测试,我的 erb 有点生锈):

<label for="rating">Rating:</label>

<%
options = [
  [10, '10 (Masterpiece)'],
  [9, '9 (Great)'],
  [8, '8 (Very Good)'],
  [7, '7 (Good)'],
  [6, '6 (Fine)'],
  [5, '5 (Average)'],
  [4, '4 (Bad)'],
  [3, '3 (Very Bad)'],
  [2, '2 (Horrible)'],
  [1, '1 (Appalling)']
]
%>

<select name="rating" id="rating">
<% options.each do |option| %>
  <option value="<%= option[0].to_s %>"<%= @anime.rating == option[0] ? ' selected' : '' %>><%= option[1] %></option>
<% end %>
</select><br>

然后删除case语句。

【讨论】:

  • 天哪,谢谢,成功了!你能向我解释一下这段代码是如何工作的逻辑吗?抱歉,我是编码新手!
  • 嗨凯蒂,我觉得可能有更好的说法,但是......我认为逻辑是对于选项数组中的每个项目(按照数组中指定的顺序)我们' 将输出一个
  • 是的,我知道三元运算符;我只是不太明白为什么选择后,另一个选项是一个空字符串?最后是选项[1]?我知道你必须迭代,只是不理解迭代的那一行!
  • 三元运算符需要三个部分,开始时的条件语句,然后(在 ? 之后)如果条件语句为真则给出的值和(在 : 之后)如果条件语句的值陈述是错误的;如果没有这三样东西,我认为你不能拥有一个三元运算符。鉴于我们不希望在与评级不匹配的情况下输出任何内容,因此空字符串将为我们执行此操作。
  • 当我们遍历选项列表中的每一项时,我们将该项的值赋给选项变量。然后这个变量包含一个数组,例如[10, '10 (Masterpiece)'] 用于第一个实例,[9, '9 (Great)'] 用于第二个实例等。要从该数组中访问 10(第一项),我们使用选项 [0];要访问“10(杰作)”,我们使用选项 [1]。我们将 option[1] 作为
【解决方案2】:

一个有用的对象可能是从数字评分到其字符串表示的映射:

@ratings_map = {
  1 => "1 (Appalling)",
  2 => "2 (Horrible)",
  3 => "3 (Very Bad)",
  etc...
}

您不必为每个评分(@oneselect、@twoselect 等)传递一个单独的变量,您可以简单地使用 @anime 本身作为所选值。然后,您可以使用 options_for_select 辅助函数:

<label for="rating">Rating:</label>

<%= options_for_select(@ratings_map.map{|key, value| [value, key]}, @anime.rating) %>

关于 options_for_select 帮助器的一些有用文档: https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select

编辑: 我很抱歉,我的头在 Rails 土地上。如果您使用的是 Sinatra,则必须在 Sinatra 应用程序顶部显式地 require 'active_support' 才能使此解决方案正常工作。您还需要确保在 Gemfile 中包含 active_support,并且 bundle install

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-22
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 2012-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多