scribble

吕小荣

Blog Friends RSS About

Rails parameter 命名习惯

17 November, 2013

Nested Model Form

1 场景

标签(label)与广告(ad)是典型的多对多的关系。

Label Class


has_many :label_ads
has_many :ads, through: :label_ads

Ad Class


has_many :label_ads
has_many :labels, through: :label_ads

LabelAd Class


belongs_to :label
belongs_to :ad

需求是:编辑label时,可以新增或删除label与ad的关系。

2 如何解决

2.1 第一种尝试

动手前先拜一拜google大神,发现 Ryan Bates 在 Railscast 讲解过类似的场景。为了尽快上线,我决定使用 Rails框架自带的功能 Nested Model Form

在做的过程中,越来越发现 Rails Nested Model form 并不能完全满足我的需求,而此时距离 deadline 只有一天了,心里开始慌张了。

期间 Vincent 和 zgm 一直劝我,不要拘泥于 Rails 的框架,框架之外的世界很精彩。

好羞愧,我现在只是个Rails程序员,不是Ruby程序员,也不是Web程序员。我是个睁眼瞎,看不到外面的世界。

2.2 第二种次尝试

2天的瞎折腾后,得出一个结论:在View层裸写表单才是唯一出路。

要想用form_tag 裸写表单,Rails parameter 的命名习惯一定要熟烂于心。

左→右,key依次递进


<%= form_tag articles_path, method: :post do %>

  <%= text_field_tag "apple[1][a]" %> 
  <%= text_field_tag "apple[2]" %>
  <%= text_field_tag "apple[3]" %>

<%=  submit_tag %>
<% end -%>

Log中提交的参数:


Parameters: {"utf8"=>"✓",
"authenticity_token"=>"iqJ4evgluTmJhVJzqkGHxkEL2gV2U8NbcJSPT3ZZiH8=", "apple"=>{"1"=>{"a"=>"X"}, "2"=>"Y", "3"=>"Z"},
"commit"=>"Save"}
 

在这个范例中,Rails是按照如下方法处理表单中的数据:

从左到右,依次为key。

中括号[]的用途

假如表单中的两个字段name相同,后面的数据就会覆盖前面的数据,比如这段代码

  1. new.html.erb
    
     <%= form_tag articles_path, method: :post do %>
       <%= text_field_tag "apple[1]" %> 
       <%= text_field_tag "apple[1]" %>
     <% end -%>
     
  2. 提交表单后,log中的parameter
    
     {"utf8"=>"✓",
     "authenticity_token"=>"iqJ4evgluTmJhVJzqkGHxkEL2gV2U8NbcJSPT3ZZiH8=",
      "apple"=>{"1"=>"b"},
      "commit"=>"Save changes"}
      

    后面的参数把前面的覆盖了,所以只剩下"1"=>"b"

但假如在name后面加一个中括号,瞬间就「有容乃大」,变成一个数组了。

  1. new.html.erb
    
     <%= form_tag articles_path, method: :post do %>
       <%= text_field_tag "apple[1][]" %> 
       <%= text_field_tag "apple[1][]" %>
     <% end -%>
     
  2. 参数
    {"utf8"=>"✓","authenticity_token"=>"iqJ4evgluTmJhVJzqkGHxkEL2gV2U8NbcJSPT3ZZiH8=",
      "apple"=>{"1"=>["a",
     "b"]},"commit"=>"Save changes"}

参考资料

  1. Rails Guide: Understanding Parameter Naming Conventions

  2. Railscast: Nested Model Form