Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Active Record Form Helpers, Season 1

2,502 views

Published on

The 11th Round of ROR Lab.

Published in: Education, Technology
  • Be the first to comment

Active Record Form Helpers, Season 1

  1. 1. The 11th Round of ROR Lab.Rails Form Helpers April 21th, 2012 Hyoseong Choi ROR Lab.
  2. 2. Short Review ROR Lab.
  3. 3. Eager Loading Associations- Conditions on Eager Loaded Associations - conditional “joins” > conditional “includes” Post.includes(:comments) .where("comments.visible", true) SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1) ROR Lab.
  4. 4. Eager Loading Associations- Conditions on Eager Loaded Associations - INNER JOIN LEFT OUTER JOIN conditional “joins” > conditional “includes” Post.includes(:comments) .where("comments.visible", true) SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1) ROR Lab.
  5. 5. Scopes Passing in argumentsclass Post < ActiveRecord::Base  scope :1_week_before, lambda { |time| where("created_at < ?", time) }endclass Post < ActiveRecord::Base  def self.1_week_before(time)    where("created_at < ?", time)  end ***What about “as a class method” ? ROR Lab.
  6. 6. Scopes Passing in arguments class Post < ActiveRecord::Base   scope :1_week_before, lambda { |time| where("created_at < ?", time) } end le eab erclass Post < ActiveRecord::Base efpr   def self.1_week_before(time)     where("created_at < ?", time)   end ***What about “as a class method” ? ROR Lab.
  7. 7. Form Helpers ROR Lab.
  8. 8. form_tag• Two arguments 1. path for action 2. options hash • submission method • HTML options : class, ... ROR Lab.
  9. 9. form_tag Basic Form<%= form_tag do %>  Form contents<% end %><form accept-charset="UTF-8" action="/home/index" method="post">  <div style="margin:0;padding:0">    <input name="utf8" type="hidden" value="✓" />    <input name="authenticity_token" type="hidden"value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />  </div>  Form contents</form> ROR Lab.
  10. 10. form_tag Multiple Hashesform_tag(:controller => "people", :action => "search", :method=> "get", :class => "nifty_form")# => <form accept-charset="UTF-8" action="/people/search?form_tag({:controller => "people", :action => "search"}, :method=> "get", :class => "nifty_form")# => <form accept-charset="UTF-8" action="/people/search" ROR Lab.
  11. 11. Helpers Generating Form Elements• check_box_tag• radio_button_tag• text_area_tag• password_field_tag• hidden_field_tag• search_field_tag• telephone_field_tag• url_field_tag• email_field_tag ROR Lab.
  12. 12. Helpers Generating Form Elements• check_box_tag• radio_button_tag• text_area_tag• password_field_tag• hidden_field_tag• search_field_tag• telephone_field_tag HTML5 controls• url_field_tag• email_field_tag ROR Lab.
  13. 13. Helpers Generating Form Elements• check_box_tag• radio_button_tag• text_area_tag• password_field_tag• hidden_field_tag polyfiller• search_field_tag• telephone_field_tag HTML5 controls• url_field_tag• email_field_tag ROR Lab.
  14. 14. Helpers Generating Form Elements• check_box_tag• radio_button_tag• text_area_tag• password_field_tag• hidden_field_tag polyfiller• search_field_tag• telephone_field_tag HTML5 controls• url_field_tag• email_field_tag ROR Lab.
  15. 15. Helpers Generating Form Elements• check_box_tag• radio_button_tag• text_area_tag yepnope• password_field_tag• hidden_field_tag polyfiller• search_field_tag• telephone_field_tag HTML5 controls• url_field_tag• email_field_tag ROR Lab.
  16. 16. Helpers Generating Form Elements• check_box_tag• radio_button_tag Modernizr• text_area_tag yepnope• password_field_tag• hidden_field_tag polyfiller• search_field_tag• telephone_field_tag HTML5 controls• url_field_tag• email_field_tag ROR Lab.
  17. 17. HTML 5 Form Helpers Rails 3 HTML5 Input Types search_field searchtelephone_field tel url_field url email_field email number_field number range_field range Agile Web Development with Rails 4th edition ROR Lab.
  18. 18. Model Object Helpers ROR Lab.
  19. 19. Model Object Helpers • check_box_tag ROR Lab.
  20. 20. Model Object Helpers • check_box_tag • radio_button_tag ROR Lab.
  21. 21. Model Object Helpers • check_box_tag • radio_button_tag • text_area_tag ROR Lab.
  22. 22. Model Object Helpers • check_box_tag • radio_button_tag • text_area_tag • password_field_tag ROR Lab.
  23. 23. Model Object Helpers • check_box_tag • radio_button_tag • text_area_tag • password_field_tag • hidden_field_tag ROR Lab.
  24. 24. Model Object Helpers • check_box_tag • radio_button_tag• No _tag • text_area_tag • password_field_tag • hidden_field_tag ROR Lab.
  25. 25. Model Object Helpers • check_box_tag • radio_button_tag• No _tag • text_area_tag • password_field_tag • hidden_field_tag ROR Lab.
  26. 26. for Model Object @person -> name : “Henry”<%= text_field(:person, :name) %><input id="person_name" name="person[name]" type="text" ROR Lab.
  27. 27. for Model Object @person -> name : “Henry”<%= text_field(:person, :name) %><input id="person_name" name="person[name]" type="text" ROR Lab.
  28. 28. for Model Object @person -> name : “Henry”<%= text_field(:person, :name) %><input id="person_name" name="person[name]" type="text" ROR Lab.
  29. 29. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  30. 30. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  31. 31. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  32. 32. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  33. 33. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  34. 34. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  35. 35. Binding a Form to an Objectdef new  @article = Article.newend<%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> ROR Lab.
  36. 36. <%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %><form accept-charset="UTF-8" action="/articles/create"method="post" class="nifty_form">  <input id="article_title" name="article[title]" size="30"type="text" />  <textarea id="article_body" name="article[body]" cols="60"rows="12"></textarea>  <input name="commit" type="submit" value="Create" /></form> ROR Lab.
  37. 37. <%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> params[:article]<form accept-charset="UTF-8" action="/articles/create"method="post" class="nifty_form">  <input id="article_title" name="article[title]" size="30" params[:article][:title]type="text" />  <textarea id="article_body" name="article[body]" cols="60"rows="12"></textarea>  <input name="commit" type="submit" value="Create" /></form>params[:article][:body] ROR Lab.
  38. 38. <%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> params[:article]<form accept-charset="UTF-8" action="/articles/create"method="post" class="nifty_form">  <input id="article_title" name="article[title]" size="30" params[:article][:title]type="text" />  <textarea id="article_body" name="article[body]" cols="60"rows="12"></textarea>  <input name="commit" type="submit" value="Create" /></form>params[:article][:body] ROR Lab.
  39. 39. <%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> params[:article]<form accept-charset="UTF-8" action="/articles/create"method="post" class="nifty_form">  <input id="article_title" name="article[title]" size="30" params[:article][:title]type="text" />  <textarea id="article_body" name="article[body]" cols="60"rows="12"></textarea>  <input name="commit" type="submit" value="Create" /></form>params[:article][:body] ROR Lab.
  40. 40. <%= form_for @article, :url => { :action => "create" }, :html =>{:class => "nifty_form"} do |f| %>  <%= f.text_field :title %>  <%= f.text_area :body, :size => "60x12" %>  <%= f.submit "Create" %><% end %> params[:article]<form accept-charset="UTF-8" action="/articles/create"method="post" class="nifty_form">  <input id="article_title" name="article[title]" size="30" params[:article][:title]type="text" />  <textarea id="article_body" name="article[body]" cols="60"rows="12"></textarea>  <input name="commit" type="submit" value="Create" /></form>params[:article][:body] ROR Lab.
  41. 41. fields_forDry Lab in Terminal ROR Lab.
  42. 42. fields_forPerson •name •age •sex •address •telephone ROR Lab.
  43. 43. fields_forPerson Contact •name •age •sex •address •telephone ROR Lab.
  44. 44. fields_forPerson Contact •name •address •age •telephone •sex ROR Lab.
  45. 45. fields_for has_onePerson Contact •name •address •age •telephone •sex ROR Lab.
  46. 46. fields_for has_onePerson Contact •name •address •age belong_to •telephone •sex ROR Lab.
  47. 47. fields_for has_onePerson Contact •name •address •age belong_to •telephone •sexclass Person < ActiveRecord::Base has_one :contact, :dependent => :destroyendclass Contact < ActiveRecord::Base belongs_to :person ROR Lab.
  48. 48. Using Resources resources :articles in config/routes.rb## Creating a new article# long-style:form_for(@article, :url => articles_path)# same thing, short-style (record identification gets used):form_for(@article) ## Editing an existing article# long-style:form_for(@article, :url => article_path(@article), :html =>{ :method => "put" })# short-style:form_for(@article) ROR Lab.
  49. 49. Using Namespacesnamespace :admin do in routes.rb  resources :posts, :commentsendform_for [:admin, @post] in _form.html.erb ROR Lab.
  50. 50. HTTP Verbs• GET for all browsers• POST• PUT ?• DELETE ROR Lab.
  51. 51. HTTP Verbs• GET for all browsers• POST• PUT ?• DELETE ROR Lab.
  52. 52. HTTP Verbs• GET for all browsers• POST• PUT ?• DELETE ROR Lab.
  53. 53. PUT & DELETE • A hidden input : _methodform_tag(search_path, :method => "put")<form accept-charset="UTF-8" action="/search" method="post">  <div style="margin:0;padding:0">    <input name="_method" type="hidden" value="put" />    <input name="utf8" type="hidden" value="✓" />    <input name="authenticity_token" type="hidden"value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />  </div>  ... ROR Lab.
  54. 54. select_tag<select name="city_id" id="city_id">  <option value="1">Lisbon</option>  <option value="2">Madrid</option>  ...  <option value="12">Berlin</option></select><%= select_tag(:city_id, <option value="1">Lisbon</option>...)%> ROR Lab.
  55. 55. options_for_select <%= options_for_select([[Lisbon, 1], [Madrid, 2], ...]) %>   output: 1st argument => a nested array   <option value="1">Lisbon</option> <option value="2">Madrid</option> ... <%= select_tag(:city_id, options_for_select(...)) %> ROR Lab.
  56. 56. options_for_select <%= options_for_select([[Lisbon, 1], [Madrid, 2], ...], 2) %>   output:   2nd argument => ‘selected’ <option value="1">Lisbon</option> <option value="2" selected="selected">Madrid</option> ROR Lab.
  57. 57. options_for_select <%= options_for_select([[Lisbon, 1], [Madrid, 2], ...], 2) %>   output:   2nd argument => ‘selected’ <option value="1">Lisbon</option> <option value="2" selected="selected">Madrid</option> ROR Lab.
  58. 58. _tag select_tag# controller:@person = Person.new(:city_id => 2)# view:<%= select(:person, :city_id, [[Lisbon, 1], [Madrid, 2], ...]) %> ROR Lab.
  59. 59. select_tag ORM for# controller:@person = Person.new(:city_id => 2)# view:<%= select(:person, :city_id, [[Lisbon, 1], [Madrid, 2], ...]) %> ROR Lab.
  60. 60. select_tag ORM for# controller:@person = Person.new(:city_id => 2)# view:<%= select(:person, :city_id, [[Lisbon, 1], [Madrid, 2], ...]) %> 2 pre-selected by Rails ROR Lab.
  61. 61. select_tag ORM for # controller: @person = Person.new(:city_id => 2) # view: <%= select(:person, :city_id, [[Lisbon, 1], [Madrid, 2], ...]) %>form builder 2 pre-selected by Rails # select on a form builder <%= f.select(:city_id, ...) %> ROR Lab.
  62. 62. select from collection<% cities_array = City.all.map { |city| [city.name, city.id] } %><%= options_for_select(cities_array) %> options _for_select ROR Lab.
  63. 63. select from collection<% cities_array = City.all.map { |city| [city.name, city.id] } %><%= options_for_select(cities_array) %> options _from_collection _for_select (City.all, :id, :name) ROR Lab.
  64. 64. collection_select<%= collection_select<%= f.collection_select ROR Lab.
  65. 65. collection_select<%= collection_ collection_select<%= f.collection_select ROR Lab.
  66. 66. collection_select<%= collection_ collection_select<%= f. f.collection_select ROR Lab.
  67. 67. Special Select• time_zone_select : time_zone_options_for_select• country_select : isolated to country_select plugin• select_date : barebones helper• date_select : model object helper ROR Lab.
  68. 68. select_date<%= select_date Date.today, :prefix => :start_date %><select id="start_date_year" name="start_date[year]"> ... </select><select id="start_date_month" name="start_date[month]"> ... </select><select id="start_date_day" name="start_date[day]"> ... </select> ROR Lab.
  69. 69. select_date<%= select_date Date.today, :prefix => :start_date %><select id="start_date_year" name="start_date[year]"> ... </select><select id="start_date_month" name="start_date[month]"> ... </select><select id="start_date_day" name="start_date[day]"> ... </select>Date.civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i) ROR Lab.
  70. 70. date_select<%= date_select :person, :birth_date %><select id="person_birth_date_1i" name="person[birth_date(1i)]"> ... </select><select id="person_birth_date_2i" name="person[birth_date(2i)]"> ... </select><select id="person_birth_date_3i" ROR Lab.
  71. 71. date_select<%= date_select :person, :birth_date %><select id="person_birth_date_1i" name="person[birth_date(1i)]"> ... </select><select id="person_birth_date_2i" name="person[birth_date(2i)]"> ... </select><select id="person_birth_date_3i"{:person => {birth_date(1i) => 2008, birth_date(2i) => 11, ROR Lab.
  72. 72. Individual Selects• select_year• select_month• select_day :prefix defaults to “date”• select_hour• select_minute• select_second ROR Lab.
  73. 73. Individual Selects• select_year• select_month• select_day :prefix defaults to “date”• select_hour• select_minute• select_second ROR Lab.
  74. 74. Uploading Filesparams[:picture] <%= form_tag({:action => :upload}, :multipart => true) do %>   <%= file_field_tag picture %> <% end %>   <%= form_for @person , :multipart => true   <%= f.file_field :picture %> do |f| %> <% end %>params[:person][:picture]Since Rails 3.1, it automatically sets the multipart/form-data with file_field in the form_for ROR Lab.
  75. 75. Uploading Filesparams[:picture] <%= form_tag({:action => :upload}, :multipart => true) do %>   <%= file_field_tag picture %> <% end %>   <%= form_for @person   <%= f.file_field :picture %> |f| %> do <% end %>params[:person][:picture]Since Rails 3.1, it automatically sets the multipart/form-data with file_field in the form_for ROR Lab.
  76. 76. Uploading Filesparams[:picture] <%= form_tag({:action => :upload}, :multipart => true) do %>   <%= file_field_tag picture %> <% end %>   <%= form_for @person   <%= f.file_field :picture %> |f| %> do <% end %>params[:person][:picture]Since Rails 3.1, it automatically sets the multipart/form-data with file_field in the form_for ROR Lab.
  77. 77. What gets uploadeddef upload  uploaded_io = params[:person][:picture]  File.open(Rails.root.join(public, uploads,uploaded_io.original_filename), w) do |file|    file.write(uploaded_io.read)  end ROR Lab.
  78. 78. What gets uploadeddef upload  uploaded_io = params[:person][:picture]  File.open(Rails.root.join(public, uploads,uploaded_io.original_filename), w) do |file|    file.write(uploaded_io.read)  endan instance of a subclass of IO • original_filename • content_type : MIME type ROR Lab.
  79. 79. Upload Gems• CarrierWave• Paperclip ROR Lab.
  80. 80. Ajaxing Upload• “remotipart” gem : AJAX style file uploads with jQuery https://github.com/leppert/remotipart ROR Lab.
  81. 81. Customizing Form Builders ROR Lab.
  82. 82. Customizing Form Builders<%= form_for @person do |f| %>  <%= text_field_with_label f, :first_name %> ROR Lab.
  83. 83. Customizing Form Builders<%= form_for @person do |f| %>  <%= text_field_with_label f, :first_name %><%= form_for @person, :builder => LabellingFormBuilder do |f|%>  <%= f.text_field :first_name %>class LabellingFormBuilder < ActionView::Helpers::FormBuilder  def text_field(attribute, options={})    label(attribute) + super  endend ROR Lab.
  84. 84. Simple_form• https://github.com/plataformatec/ simple_form ROR Lab.
  85. 85. Params Naming Client Server Formfor model obj “@person” params[:person] submit ROR Lab.
  86. 86. Params Naming Client Server Formfor model obj “@person” params[:person] submit ROR Lab.
  87. 87. Basic Structures Arrays & Hashes<input id="person_name" name="person[name]" type="text" value="Henry"/>params hash {‘person’ => {‘name’ => ‘Henry’}}params[:person] {‘name’ => ‘Henry’}params[:person][:name] ‘Henry’ ROR Lab.
  88. 88. Nested Hashes<input id="person_address_city" name="person[address][city]" type="text" value="New York"/>params hash {person => {address => {city => New York}}} ROR Lab.
  89. 89. Duplicated Params <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/>params[:person][:phone_number] [ ’02-333-1234’, ‘031-323-9898’, ‘062-546-2323’ ] ROR Lab.
  90. 90. Duplicated Params <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/>params[:person][:phone_number] [ ’02-333-1234’, ‘031-323-9898’, ‘062-546-2323’ ] ROR Lab.
  91. 91. Duplicated Params <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/>params[:person][:phone_number] [ ’02-333-1234’, ‘031-323-9898’, ‘062-546-2323’ ] ROR Lab.
  92. 92. Duplicated Params <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/> <input name="person[phone_number][]" type="text"/>params[:person][:phone_number] [ ’02-333-1234’, ‘031-323-9898’, ‘062-546-2323’ ] ROR Lab.
  93. 93. Mixed Params hash nth-nested but array only one-level<input name="addresses[][line1]" type="text"/><input name="addresses[][line2]" type="text"/><input name="addresses[][city]" type="text"/>params[:addresses] [ { ‘line1’ => ’02-333-1234’, ‘line2’ => ‘031-323-9898’, ‘city’ => ‘seoul’ } ] ROR Lab.
  94. 94. Using Form Helpers<%= form_for @person do |person_form| %>  <%= person_form.text_field :name %>  <% @person.addresses.each do |address| %>    <%= person_form.fields_for address, :index => address do |address_form|%>      <%= address_form.text_field :city %>    <% end %>  <% end %><% end %><form accept-charset="UTF-8" action="/people/1" class="edit_person" id="edit_person_1"method="post">  <input id="person_name" name="person[name]" size="30" type="text" />  <input id="person_address_23_city" name="person[address][23][city]" size="30" type="text" />  <input id="person_address_45_city" name="person[address][45][city]" size="30" type="text" /></form> ROR Lab.
  95. 95. Using Form Helpers{ person => { name => Bob, address => { 23 => {city => Paris}, 45 => {city => London} } } ROR Lab.
  96. 96. Using :index<%= fields_for person[address][primary], address, :index =>address do |address_form| %>  <%= address_form.text_field :city %><%= fields_for person[address][primary][], address do |address_form| %>  <%= address_form.text_field :city %> ROR Lab.
  97. 97. Form to External Resources - 1<%= form_tag http://farfar.away/form, :authenticity_token =>external_token) do %>  Form contents<%= form_tag http://farfar.away/form, :authenticity_token =>false) do %>  Form contents ROR Lab.
  98. 98. Form to External Resources - 1<%= form_tag http://farfar.away/form, :authenticity_token =>external_token) do %>  Form contents payment gateway<%= form_tag http://farfar.away/form, :authenticity_token =>false) do %>  Form contents ROR Lab.
  99. 99. Form to External Resources - 1<%= form_tag http://farfar.away/form, :authenticity_token =>external_token) do %>  Form contents<%= form_tag http://farfar.away/form, :authenticity_token =>false) do %>  Form contents payment gateway ROR Lab.
  100. 100. Form to External Resources - 2<%= form_for @invoice, :url =>external_url, :authenticity_token => external_token do |f|  Form contents<% end %><%= form_for @invoice, :url =>external_url, :authenticity_token => false do |f|  Form contents ROR Lab.
  101. 101. Form to External Resources - 2<%= form_for @invoice, :url => form_forexternal_url, :authenticity_token => external_token do |f|  Form contents<% end %><%= form_for @invoice, :url => form_forexternal_url, :authenticity_token => false do |f|  Form contents ROR Lab.
  102. 102. Complex formsRailscasts by Ryan Bates ROR Lab.
  103. 103. Complex formsRailscasts by Ryan Bates• Complex Forms Part 1 - Episode #73• Complex Forms Part II - Episode #74• Complex Forms Part III - Episode #75• Nested Model Form (resivsed) - Episode #196 ROR Lab.
  104. 104. 감사합니다.
  105. 105.   ROR Lab.

×