2012-12-09 20 views
13

高度以英寸存儲在數據庫中。將多輸入虛擬屬性移動到SimpleForm自定義輸入組件

然而英尺和英寸需要自己單獨的輸入形式:

Height: [_______] feet [_______] inches 

所以我用虛擬屬性,並得到了它的工作。這裏是我的模型的簡化版本:

class Client < ActiveRecord::Base 
    attr_accessible :name, :height_feet, :height_inches 

    before_save :combine_height 

    def height_feet 
     height.floor/12 if height 
    end 

    def height_feet=(feet) 
     @feet = feet 
    end 

    def height_inches 
     if height && height%12 != 0 
     height%12 
     end 
    end 

    def height_inches=(inches) #on save? 
     @inches = inches 
    end 

    def combine_height 
    self.height = @feet.to_d*12 + @inches.to_d #if @feet.present? 
    end 

end 

而且_form部分使用simple_form:

<%= simple_form_for(@client) do |f| %> 
    <ul> 
    <%= f.error_notification %> 
    <%= f.input :name %> 
    <%= f.input :weight %> 
    <li> 
     <%= f.input :height_feet, :label => 'Height', :wrapper => false %> 
     <span>feet</span> 
     <%= f.input :height_inches, :label => false, :wrapper => false %> 
     <span>inches</span> 
    </li> 
    <%= f.error :base %> 
    </ul> 
    <%= f.button :submit %> 
<% end %> 

這工作。不過這是不理想的。

我想幹這個並創建一個custom input component,所以我可以使用<%= f.input :height, as: :feet_and_inch %>將表格高度添加到表格中,因此可以使用其他任何類似<%= f.input :wingspan, as: :feet_and_inch %>的圖案。

我已經對自定義組件進行了實驗,但是我無法獲得兩個輸入來顯示 - 而且我不確定哪裏是將轉換邏輯從英尺和英寸放到英寸的最佳位置(同樣也是如此從英寸到英尺和英寸)。

+0

爲什麼不使用簡單的輔助方法?對於我來說,不需要添加自定義輸入組件......而且,接收表單構建器的輔助方法是執行所需內容的最簡單,最乾燥的方式,我認爲。 :)對於轉換邏輯,它取決於你在哪裏使用這些邏輯......如果它只是在視圖中,然後把它們放在輔助方法中,否則模型是一個好地方。 – Kulgar

+0

我希望深入一點的原因之一是,在當前的實現中,錯誤消息顯示在英尺和英寸輸入之間,而不是在兩者之後,將它們移動到輔助方法不會解決這個。感謝您的意見,但! – bookcasey

+0

如果任何人有興趣,這是一個非常頭痛的問題,我決定使用一個選擇元素,如'5'10'','5'11','6','val'設置在英寸(70,71,72),這是不難做一個小循環。 – bookcasey

回答

6

據我所知,除了渲染到自定義輸入之外,你無法真正移動任何東西。一旦表單被提交,SimpleForm就不會被調用,所以它不能以任何方式真正干擾這些值。如果我以前也需要這樣做,我很樂意錯誤。無論如何,這是一個保持模型中轉換邏輯的版本。

定製SimpleForm輸入:

# app/inputs/feet_and_inch_input.rb 
class FeetAndInchInput < SimpleForm::Inputs::Base 
    def input 
    output   = "" 
    label   = @options.fetch(:label) { @attribute_name.to_s.capitalize } 

    feet_attribute = "#{attribute_name}_feet".to_sym 
    inches_attribute = "#{attribute_name}_inches".to_sym 

    output << @builder.input(feet_attribute, wrapper: false, label: label) 
    output << template.content_tag(:span, " feet ") 
    output << @builder.input(inches_attribute, wrapper: false, label: false) 
    output << template.content_tag(:span, " inches ") 

    output.html_safe 
    end 

    def label 
    "" 
    end 
end 

形式。請注意,我沒有將<li>標籤放入自定義輸入內,我認爲這樣更靈活,但可以隨意更改。

# app/views/clients/_form.html.erb 
<li> 
    <%= f.input :height, as: :feet_and_inch %> 
</li> 

所有這一切都依賴於一個事實,每height屬性,你也有height_feetheight_inches屬性。

現在的模型,我不會真的知道這是去了,也許有人會想出更好的解決方案的方式,但這裏有雲:

class Client < ActiveRecord::Base 
    attr_accessible :name 

    ["height", "weight"].each do |attribute| 
    attr_accessible "#{attribute}_feet".to_sym 
    attr_accessible "#{attribute}_inches".to_sym 

    before_save do 
     feet = instance_variable_get("@#{attribute}_feet_ins_var").to_d 
     inches = instance_variable_get("@#{attribute}_inches_ins_var").to_d 

     self.send("#{attribute}=", feet*12 + inches) 
    end 

    define_method "#{attribute}_feet" do 
     value = self.send(attribute) 
     value.floor/12 if value 
    end 

    define_method "#{attribute}_feet=" do |feet| 
     instance_variable_set("@#{attribute}_feet_ins_var", feet) 
    end 

    define_method "#{attribute}_inches=" do |inches| 
     instance_variable_set("@#{attribute}_inches_ins_var", inches) 
    end 

    define_method "#{attribute}_inches" do 
     value = self.send(attribute) 
     value % 12 if value && value % 12 != 0 
    end 
    end 
end 

,它基本上是相同的,但定義方法動態。您可以在頂部看到您想要生成這些方法的屬性列表。

請注意,所有這些都沒有經過徹底測試,可能會殺死你的貓,但希望能給你一些想法。

+0

我認爲這是一個不錯的解決方案,絕對聰明的想法。 –

2

我的拙見認爲,如果用戶只在一個字段中輸入數據,您會給用戶更好的體驗。以下是我的擔憂:

假設您使用的高度範圍有限(可能是人的身高),您可以編寫驗證來檢測用戶輸入是什麼 - 英寸或英尺。然後你可以創建一個驗證鏈接(或者更好的一個按鈕),詢問輸入是什麼意思(檢測到英寸或英尺)。所有這些(包括尺寸轉換,只是英寸 - >英尺)都可以在javascript中完成,您可以通過Ajax調用獲取當前尺寸,並避免重新加載頁面的整個代碼。

編輯:我發現一個interesting point of view與複雜的輸入有關。另一個useful resource關於填充用英尺和英寸形式的用戶交互。

您的問題非常有趣,我很樂意看到您選擇的解決方案。

+0

我已經考慮了很多,我認爲兩個輸入是用戶體驗的理想,即使它實施起來更棘手。我個人更喜歡鍵入'5'選項卡'10',而不是在'''和'''的鍵盤上釣魚(特別是在移動設備上),或者強迫用戶輸入「5英尺10英寸」。像這樣在沒有Javascript的情況下工作是理想的。感謝您的想法! – bookcasey