simple_form non-model inputs

遇到的問題:

在使用simple_form_for的時候,input都需要對應到model table 的欄位像是下面這樣

index.html.erb
<=% simple_form_for [:add_product_to_cart ,@product] ,method: :post do |f| %>
<% f.input:name %>#input後面會加上Product有的欄位
<% end %>

但是有時候想要post某些資料,但是table卻沒有這個欄位時,用一樣的方法就會報錯
舉個小例子,先上code

productController.rb
def add_product_to_cart
    @product = Product.find(params[:id])
    current_cart.add_product_to_cart(@product)
end
cart.rb
class Cart < ActiveRecord::Base
  has_many :cart_items , dependent: :destroy
  has_many :items , through: :cart_items , source: :product

  def add_product_to_cart(product)
    cart_item = cart_items.build
    cart_item.product = product
    cart_item.save
  end
end

假設今天要在把product(產品)加入cart(購物車)時順便把選取的數量一起post到server,在把product資料post到add_product_to_cart這個action得時候,我還想要順便傳購買數量,但是product卻沒有oreder_quantity的的欄位,這個欄位實際上是放在紀錄購物車明細的cart_items裡,所以如果我code寫f.input:oreder_quantity就會報錯。

解法

解法一

使用text_field_tag

show.html.erb
<%= simple_form_for [:add_product_to_cart , @product] , method: :post do |f| %>
    <%= f.input :order_quantity,label: false do %>
    <%= text_field_tag 'order_quantity',"1",class:"form-control",id:"modal-qty",data:{rule:"quantity"} %>
  <% end %>
<% end %>

說明

f.input後面的symbol可以自定義想叫什麼都可以,程式上並不會用到,label:false是不會顯示標籤這個要不要加就看個人,重點是在text_field_tag這邊,其實text_field_tag不是simple_form裡面的method,而是rails裡面的helper,大概的用法是這樣text_field_tag(name, value = nil, options = {}),第一個參數是post到action後在params裡要用什麼key值把資料取出來,第二個就是預設值了,第三個如果需要額外加上html arrtibute的話就加在這邊,例如class之類的,詳細可以看這邊text_field_tag,這action裡就可以使用params[:order_quantity]取值。

解法二

使用simple_fields_for
如果有一次想要傳多個值過去的話我比較推薦這個方法

show.html.erb
<%= simple_form_for [:add_product_to_cart , @product] , method: :post do |f| %>
  <%= simple_fields_for :data do |o| %>
    <%= o.input :params1,label: false  %>
    <%= o.input :params2,label: false  %>
    <%= o.input :params3,label: false  %>
  <% end %>
<% end %>

說明

simple_fields_for的用法就跟上面的text_field_tag用法很不一樣了,要注意的點有幾點
1.simple_fields_for後面的symbol是在params裡面的key值。
2.input裡面的symbol是params裡二維陣列的key值。
3.用input_html給input加上id attribute是無效的,id會被自動加上,會是simple_fields_for的symbol+input的symbol,以上面的例子來看第一個input的id就會是id="data[params1]"
4.在controller取值要用二維的方法取值

controller.rb
p1 = params[:data][:params1]
p2 = params[:data][:params2]
。。。以此類推

5.如果要custom input的內容的話要自己加上name屬性,name的名稱也是simple_fields_for的symbol+input的symbol,以這邊的例子就是name="data[params1]",要記得取name名稱資料才會傳的過去,然後這邊跟上面不一樣的地方是,如果是用這種block的input裡面的input element就可以取id名稱不會被覆蓋。

show.html.erb
<%= simple_fields_for :data do |o| %>
  <%= o.input :params1,label: false do %>
    <input type="text" class="form-control" id="modal-qty" value="1" data-rule="quantity" name="data[params1]">
  <% end %>
<% end %>

以上就是踩雷之後的小小紀錄

參考資料

simple_form
text_field_tag
Rails Simpleform with non-model inputs
rails simple_form fields not related to the model

comments powered by Disqus