Ruby on rails, split a big form into separate smaller forms - ruby-on-rails

Could not find the answer to the question on how to split forms in rails in multiple smaller forms.
Say you have a big form with
firstname
lastname
gender
age
email
country
city
state
I have a validate_presence for all these fields. So when I create several forms like:
= simple_form_for #profile, :wrapper => :inline do |f|
= f.label "firstname"
= f.select :firstname
without all the values from the top list (first name,last name,etc) I get errors because the splitter form does not contain those values and they need to be present at first to make this work at all.
What would be a good way to have several forms but with only a portion of the values and update them without getting the issue described above?

If you want the ability to update pieces of the model then you need to split the validations into pieces as well.
One way to do it is to have a virtual attribute in your model that gets set by a hidden field in each form. E.g you may have a form:
= simple_form_for #profile, :wrapper => :inline do |f|
= f.hidden :form, :input_html => {:value => 'names'}
= f.label "firstname"
= f.select :firstname
Then in your model:
class Profile
attr_accessor :form
validates :firstname, :presence => true, :if => lambda { |o| o.form == "names" }
end
The validation will run only if the change was submitted from the right form.
Check out conditional validation guide: http://guides.rubyonrails.org/active_record_validations_callbacks.html#conditional-validation for more details.
Other way is a multistep form as suggested by apneadiving: http://railscasts.com/episodes/217-multistep-forms This uses the same technique as in the first example by having a current_step attribute, but the progression is linear.

You're asking for a multi step form I guess.
Look at this screencast, you'll find conditional validations which are the way to proceed.

Related

ActiveAdmin: display parameter of object selected in form

I am not very familiar with ActiveAdmin or rails in general, so sorry if I use some incorrect phrasing.
I have a model for an Athlete, which has an attribute "notes". This is described in the permit_params of the athlete.rb.
On an additional page, I have the following:
f.input :athlete, :collection => Athlete.all.sort_by(&:last_name), :required => true
I would like to find a way to, if the :notes is not empty, display it.
If I could display it as a "row" on the form, that would be great.
Thanks!

Money Rails Gem - null values

I have monetised two models of my Rails 4 app with Money-Rails gem.
One is called Participants, the other is called Funding. Each of these models is nested inside another model, called Scope. Scope belongs to Project.
The associations are:
Project has one Scope; Scope belongs to Project
Scope has one Participant and has one funding; each of Participant and Funding belong to Scope.
Project accepts nested attributes for Scope. Scope accepts nested attributes for Participant and Funding.
Params for each relevant attribute in Participant and Funding are permitted in the Scope and Project Controllers as well as the models themselves. Params for Scope are permitted in the Scope and Project controllers.
In my Project form, I ask several questions. That form also has nested forms for each of the models which belong to it. Inside the Scope form, I ask users two boolean questions, being: Do you want participants? Do you want funding? Each of these models has a follow up question about participation cost and funding (those attributes are monetised).
If the answer to those questions is true, then I reveal the participant or funding form partial and ask how much money they want.
I have two problems:
First problem: Not null violation
1. If a user says they do want participants, but there is no associated costs, so that the boolean question inside the participant model asking whether there is cost involved with participation, I get an error that says:
ERROR: null value in column "participation_cost_pennies" violates not-null constraint
If a user says they don't want participants in answer to the question asked in the Scope form, I get the same error as in 1 above
Second problem: If I save an amount in the monetised fields, and come back to edit the project form, the form does not show the saved amount in the monetised field - and if you don't reenter it, I get an error saying that it can't be blank.
Does anyone know how to:
make the first problem go away in all circumstances except those when participation costs are actually sought; and
Fix the second problem by displaying the original amount saved when you come back to edit the form? I have tried inserting :selected into my form element, but it doesn't do anything.
My code is as follows:
Inside my Scope form (nested inside my project form):
<%= f.simple_fields_for :scope do |s_all| %>
<%= s_all.input :if_participant, :as => :boolean, :label => false, inline_label: 'Public participants or volunteers' %>
<%= s_all.input :if_funding, :as => :boolean, :label => false, inline_label: 'Funding or expenses' %>
If the answer to these fields is true, then I reveal the partial forms for participant of funding (for whichever is true).
Inside my Participants partial form, I have:
<%= f.simple_fields_for :scope do |participants_s| %>
<%= participants_s.simple_fields_for :participant do |par| %>
<%= f.label 'Are participants reimbursed for their costs?', :class => 'question-project' %>
<%= par.collection_radio_buttons :costs, [[true, ' Yes'], [false, ' No']], :first, :last, {:item_wrapper_class => 'fixradio'}, {:class => "response-project"} %>
<%= f.label 'What amount will you pay for participation costs?', :class => 'question-project' %>
<%= par.select :participation_cost_currency,
options_for_select(major_currencies(Money::Currency.table)), selected: :participation_cost_currency,
label: false,
prompt: "Select your costs currency" %>
<%= par.input :participation_cost, label: false, placeholder: 'Whole numbers only', selected: :participation_cost_pennies, :input_html => {:style => 'width: 250px; margin-top: 20px', class: 'response-project'} %>
For the first problem, you'll want to set a default value for the participation_cost_cents column in a migration:
# in console
> rails g migration change_default_for_participation_cost_cents
# in migration file
class ChangeDefaultForParticipationCostCents < ActiveRecord::Migration
def change
change_column :participants, :participation_cost_cents, :integer, default: 0
end
end
I'm not sure I follow on the second problem though. Maybe you should split the question in two?
A meetup group for Rails has helped me answer this question. The answer is not obvious - especially for newcomers.
My problem was I had an attribute in my database called participation_cost. Monetise then tried to make a method with the same name and that was failing because of the attribute in my table. For others, you don't need the attribute in your database with the name of the field you want to monetise.
Removing that attribute (in my case, participation_cost) solved my problem.

semantic_field_for for arbitrary attribute

I am quit new to rails. I have been using formtastic in my project and I find it quite easy to deal with the form objects. I have a small problem which I hope to clear out here.
I want to create a form for arbitrary objects and a has_many type of nested form for it. What I mean is semantic_form_for does not use any model instead uses symbol for creating form and this form now has to have a to_many type of semantic_fields_for. This is how my code looks,
= semantic_form_for :company do |f|
= f.inputs "company" do
= f.input :name
= f.input :enterprise_code
= f.semantic_fields_for :email do |e|
= f.inputs "email" do
= f.input :address
The form above is not associated to any model. I will pick these attributes in the controller and assign it individually. The email fields in the form has to be like has_many. Now, it is like one to one. How can this be achieved.
I used formtastic only once so i might be wrong but i don't think there's anything mentioned that you can use it only for one type of association. It only says that you for nested forms we can use semantic_fields_for :model and then both model's must be setup correctly with accepts_nested_attributes_for

HAML - how to create form validation and display error messages?

I am able to render a form in HAML but I am not sure how to validate it.
Here is what I have so far:
#disclosure-form-container
= form_for([:mobile,#disclosure], :html => {:id => "disclosure-form", :remote => true}) do |f|
%p
=f.label :display_as, (t :select_disclosure_type)
=f.select :display_as, options_from_collection_for_select(Disclosure.basics, :display_as, :name, f.object.display_as)
%p
=f.label :notes, (t :notes)
=f.text_area :notes, :class => "#{validation_rules(:free_disclosure_notes)}", :rows => 5 , :id => "disclosure_notes_entry"
= buttonset({:submit_label => (t "buttons.influencers.disclosures.create"),:submit_css_class => "call-to-action",:cancel_url => "#",:direction => :left_to_right})
This renders a form with two fields and a button to click submit. But what if people just enter submit without doing much? Where do I put the validation code and how do I validate this form?
Thanks!
A user enters data that should be saved in your model and then stored in your DB. So it's naturally to implement validation on model-level. Rails allows you to create validation for models easy. Here you can read about it. In a few words: adding few lines to your model prevent it to be saved with inconsistent data.
But you can in addition to model-level validation use client-side validation: i.e., data will be checked before sending to server. This way user don't have to submit form to find out that he forgot to fill some required field. But of course this can't be any guaranty as it's easy to bypass. Here more about client-side validation.
So, as you see, Haml can't help you with validations. It's a great tool, but not for this purpose.
In your Disclosure model, you need:
class Disclosure < ActiveRecord::Base
validates_presence_of :display_as, :notes
...
end
Then you can include error messages at the top of your form with something like:
- if #disclosure.errors.any?
%ul.errors
- #disclosure.errors.full_messages.each do |msg|
%li= msg
Or if you use Simple Form you get automatic validation messages inline, and your form would just look like this:
= simple_form_for #disclosure do |f|
= f.input :display_as
= f.input :notes
= f.submit
And you're done.
Note, as Jdoe pointed out, HAML has nothing to do with detecting validations, it only displays what the server tells it. The server is what determines whether there are validation errors.
If you want to try and come up with the equivalent of something like this client side you could give your form an id and do something like this (in CoffeeScript):
jQuery ->
$('form#disclosures').submit (event) ->
unless $('input#display_as').val().length > 0 && $('input#notes').val().length > 0
event.preventDefault()
$(this).append('<div class="error">You must select 'display' and enter notes.</div>')

Formtastic non-model form, integration with external site, override/specify the input ID values

I'm using formtastic to collect information from a form and post dirctly to an external site.
I have no problem generating the form itself. However, since this is being submitted to an external site, they require that each input field have the specific IDs they specify, eg email or last_name -- not the closest Formtastic form, eg _email_input or _last_name_input.
I've looked at the Formtastic v1.2.3 code and I'm 90% sure the answer is "sorry, can't do that." I figured it couldn't hurt to check if I'm missing something. I would like some way to specify the ID completely, as in:
= semantic_form_for('', :url => "https://external_site.com/handler, :method => "post") do |form|
= form.input :last_name, :id => "last_name"
[etc]
Is this possible?
(I will note that I recognize that another, arguably superior approach would be to create an appropriate controller, sanity check the parameters locally, and dispatch the remote call from within the app only when it's well formed; however, that's not what I'm trying to do at the moment.)
Firstly i think you need to use semantic_fields_for for non-model forms. Next, to pass ids to each field, you can use the input_html options to specify them. for eg
form.input :email, :input_html => {:name => 'email', :id => 'email' }

Resources