创建跨多个不同布局的模块化表单的最佳实践

时间:2013-08-20 15:54:44

标签: ruby-on-rails ruby forms ruby-on-rails-3.2 partials

我是一个RoR新手(v3.2.13),我正在构建一个新的网站/应用程序,它有很多登陆页面,分为6-8种不同的布局。布局在更改顺序中使用类似的元素,因此我使用partials和layout继承来适当地呈现每个页面。

我的问题是我的表单(位于每个页面的顶部)也不一致(例如,一个页面可能只有一个“名称”和“电子邮件”字段,另一个页面将包含一个额外的“电话”字段,第三个可能还包括“密码”,“地址”和“国家”字段等),并为每个页面构建不同的部分看起来像一个非常浪费的方法,干嘛明智,更不用说它是多么无效特别是因为我预计将来会有大量的新页面。

我已经彻底研究了表单概念,但还没有找到一个我认为足够好的解决方案,可能是因为我是一个新手。不幸的是,我没有任何代码要呈现,因为我一直等到我决定开始编码的最佳方法。

到目前为止,我想到的是在Haml中使用jQuery和条件,我理解它们都是天真的方法,而我将每个字段编码为自己的部分将被视为反模式(或者 - 不是Rails 3方式)。

是否有与此类设计问题相关的最佳做法?是否有任何我错过的在线/其他资源会让我指向正确的方向?

谢谢!

2 个答案:

答案 0 :(得分:3)

我会通过构建包含所有元素的单个表单来解决这个问题,将其放在部分表单中,并将其包含在所有登录页面上。然后在每个登录页面的各个样式表中,隐藏您不想在该特定页面上使用的所有元素。

要解决验证的潜在问题(例如,您需要验证是否在请求时提供了密码),您可以创建一个配置文件(例如config/initializers/landing_forms.rb),您可以在其中指定要在每个表单中包含哪些表单字段,然后从该文件生成适当的CSS,并在验证中使用它,即:

landing_forms.rb

YourInitializer = {
  foo: [:email, :password],
  bar: [:email, :name, :address],
  baz: [:name, :phone]
}.with_indifferent_access.freeze

_form.html.erb

<%= form_for ... do |f| %>
  <%= f.hidden_field_tag :landing_page_id, value: 'foobar' %>
<% end %>

控制器

class UsersController < ApplicationController
  def create
    @user = User.new(params[:user])
    User.validate_only requested_fields
    # ...
  end
protected
  def requested_fields
    YourConfig.fetch params[:landing_page_id]
  end
end

模型

class User < ActiveRecord::Base
  attr_reader :required_validations
  validate :email, presence: true, if: :email_required?

  def email_required? # feel free to use a bit of metaprogramming to make this simpler
    required_validations.include? :email
  end

  def validate_only(fields)
    @required_validations = fields
  end
end

page_forms.css.erb

/* Hide all non-button inputs by default, then show individually */
<% YourConfig.each_pair do |landing_page_id, fields| %>
  <% fields.each do |field| %>
    #<%= landing_page_id %> form .<% field %> { display: block }
  <% end %>
<% end %>

希望这足以让你入门!

答案 1 :(得分:0)

这种结构怎么样?

# Controller
@fields = [:name, :country, :phone]

# View
@fields.each do |field|
   render "form/" + field.to_s
end

# form/name.html.erb
<%= text_field(:name) %>