Question

I'm a RoR newbie (v3.2.13), and I'm building a new site/application that has a lot of landing pages, divided into 6-8 different layouts. The layouts are using similar elements in a changing order, so I'm using partials and layout inheritance to render each page appropriately.

My problem is that my forms (located at the top of each page) are also inconsistent (for example, while one page might only have a "name" and "email" fields, another will contain an additional "phone" field, a third one might also include a "password", "address" and "country" fields, etc.), and building a different partial for each page seems like a very prodigal approach, DRY wise, not to mention how ineffective it is, especially since I expect a vast amount of new pages in the future.

I've researched the forms concept thoroughly but have yet to come up with a solution that I deem good enough, probably due to me being a newbie. Unfortunately I don't have any code to present, since I waited until I make a decision regarding the optimal approach to start coding.

What I came up with so far is using jQuery and conditionals within Haml, which I understand are both naive approaches, while I read coding each field into its own partial would be considered an anti-pattern (alternatively - NOT the Rails 3 way).

Is there a best practice pertaining to such design issues? Are there any online/other resources I missed that would point me in the right direction?

Thanks!

Was it helpful?

Solution

I would solve this by building a single form with all of the elements, putting it in a partial, and including it on all of the landing pages. Then in the individual stylesheets for each landing page, hide all of the elements that you don't want to use on that particular page.

To solve potential problems with validations (e.g. you need to validate that a password was given when requested) you can create a configuration file (e.g. config/initializers/landing_forms.rb) where you specify which form fields are to be included in each, then generate the appropriate CSS from that file and also use it in your validations, i.e.:

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 %>

controller

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

model

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 %>

Hopefully that's enough to get you started!

OTHER TIPS

How about this sort of structure?

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

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

# form/name.html.erb
<%= text_field(:name) %>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top