简体   繁体   中英

How to render different forms built on the same model in rails

I'm building an application where users can sign up, browse grants and then apply to the ones that they qualify for. So far I have models for each: users, grants, and applications. To summarize the user clicks an apply button on the grant page, they are sent to a unique form that is specific to that grant which they fill out as their application. The part I'm struggling with is that each grant will have a unique application form.

My thought so far is to have all possible fields in the application model and then have multiple partials (with only the fields necessary for that grant) that are called based on the grant id. I tried changing the render on submissions/new to:

<%= render :partial => "submissions/#{@grant}" %> 

which intends to render the partial based on the grant_id of the previously visited grant page.

_submission/1.html.erb
_submission/2.html.erb
_submission/3.html.erb  

This doesn't work as is but I'm not sure what I'm missing.

Another idea is to add a separate submission model that will link grants and applications through a join table but I still have the problem of calling a unique form for each grant.

Does anyone have a solution to the render problem or suggestions of alternate methods of creating many unique applications without building a new model for each?

I had to implement something similar to this recently. I rendered the same form in multiple locations across the site, but assigned them a unique content_type through a hidden field tag. Based on their content type that was attached to the form, the appropriate email would be sent out to them. I'll list the process I used, I think it can be easily modified to suit your needs.

First I created a migration called contacts. For you I guess it would be applications?

rails g migration contacts

Then i added the following fields,

class CreateContacts < ActiveRecord::Migration
  def change
    create_table :contacts do |t|
      t.string :name
      t.string :phone
      t.string :email
      t.text :comment
      t.string :content_type


      t.timestamps
    end
  end
end

Add whatever fields you feel necessary for your application. Keep content_type though.

rake db:migrate

I then generated a contacts controller

rails g controller Contacts

,and filled it out as below. Pretty standard but take note of content_type being one of our permitted parameters.

class ContactsController < ApplicationController

    def new
        @contact = Contact.new
    end

    def create
        @contact = Contact.new(contact_params)

        if @contact.save
            flash[:success] = "Message Sent!"
            redirect_to root_path
        else
            flash[:danger] = "Error occurred"
            render :new
        end
    end

    private
        def contact_params
            params.require(:contact).permit(:name, :phone, :email, :comment, :contact_type)
        end
end

Now our form. Under the views/contacts folder that has been generated, create a folder and call it partials . Within this folder create a file and call it _form.html.erb .The underscore is important as it's a partial. Sorry if i'm over explaining some things.

_form.html.erb

<%= form_tag contacts_path do %>
   <%= hidden_field_tag 'contact[contact_type]', contact_type %>

   <%= text_field_tag 'contact[name]', nil, required: true, placeholder: "Name" %>

   <%= text_field_tag 'contact[phone]', nil, placeholder: "Phone" %>

   <%= email_field_tag 'contact[email]', nil, required: true, placeholder: "Email" %>

   <%= text_area_tag 'contact[comment]', nil, required: true, placeholder: "Comments" %>

   <%= submit_tag "Submit" %>
<% end %>

Then in my views, wherever I want a form or application in your case, I would render the form partial and add the contact type. You could leave it as contact_type or call it application_type or whatever you want when you first generate your migration as above.

<%= render partial: '/contacts/partials/form', locals: {contact_type: 'become_partner'} %>

In my contact model contact.rb , I would add some validations on the fields I must have, and also write a method for calling my ContactMailer(which i haven't created yet).

class Contact < ActiveRecord::Base
    validates :name, presence: true
    validates :email, presence: true

    after_create :send_email

    private
        def send_email
            if self.contact_type == 'become_partner'
                ContactMailer.partner_email(self).deliver
            else
                ContactMailer.contact_email(self).deliver
            end
        end
end

Our send_email method is where we will query the type of content_type attached to the form. You may have

if self.contact_type == 'application_1(for example)'
      ContactMailer.application_1(self).deliver
elsif self.contact_type == 'application_2'
      ContactMailer.application_2(self).deliver
else
      ContactMailer.application_3(self).deliver
end

Add as many elsif as you need.

Let's now create our contact mailer. In the folder app/mailers create the file contact_mailer.rb

class ContactMailer < ActionMailer::Base
    default to: 'justin@socialplayground.com.au'

    def contact_email(contact)
        @contact = contact

        mail(from: @contact.email, subject: 'Contact Form Message').deliver
    end

    def partner_email(contact)
        @contact = contact

        mail(from: @contact.email, subject: 'Contact Form Message').deliver
    end

end

Here we create all the actions for our different forms to send each their own email. In the above example I had contact_email as my main homepage form, partner_email for the form in the partner signup section etc. You may have application_1, application_2 etc, and feel free to change the subject to whatever you want. This is what shows up in your email inbox before you open it. The name of the sender and the brief message, so "new application for ... " in your case, for example.

AND FINALLY..

Our html email that gets sent. Under views create a folder called contact_mailer , and within this folder create the emails with the associated names. So for me, for my main home page form I had the email contact_email.html.erb , my partner form I created partner_email.html.erb .

<!DOCTYPE Html>
<html>
    <head>
        <title></title>
    </head>
    <body>

        <p>New message from RuNpiXelruN's Contact Form!, from <%= "#{@contact.name}, #{@contact.email}" %></p>
        </br>
        <p><%= @contact.name %></p>
        <p><%= @contact.phone %></p>
        <p><%= @contact.comment %></p>

    </body>
</html>

This is what will be in the email when you open it up. Change the message as you please.

All should now work smoothly, using only one form and model for your entire site!

Also, I meant to mention that if you have some fields that are specific to some applications, create them when you do your initial migration and query for the content_type in the main _form partial. ie if content_type is ..this.. text_field_tag 'contact[...example..]'

for example.

One more thing, now that we are using one form, and one create method, it makes it a little difficult to render :new in our controller if there is an error. This is why you may have noticed that I've added the required: true to the inputs of the form I need, to handle errors here. That way the form won't be allowed to submit unless it has been filled correctly.

Test and make sure all the cogs are turning correctly. Watch your server log as it's happening. I deployed my app to Heroku. To get this to actually email, you need one more configuration step. I handled it with sendgrid. If you don't know how, and you get all this working as you'd like, reach out and i'll show you. Good luck!

Justin

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM