I'm using the High Voltage gem (https://github.com/thoughtbot/high_voltage/) for a site with masses of static pages. The site has three unique forms all which are handled by the 'forms' controller/model.
Now all is working well when fields which requires validation are populated, but when validation fails it jumps from the 'pages' controller (High Voltage) back to the 'forms' controller and renders /form/new, instead of, for instance, /pages/quotes - which is understandable as it's default behaviour.
I'm also checking for validation in the form:
= form_for #form, :validate => true do |f|
- if #form.errors[:name].present?
.control-group.error
= f.label "Your Name"
= f.text_field :name
- else
= f.label "Your Name"
= f.text_field :name
Any idea how I can re-render the current page (which renders the specific form) after validation fails instead of directing to /forms/new
Any advice appreciated, thanks!
Related
I'm creating a form with a .select field that loads a list of states via partial. The requirement isn't being enforced on state and I'm not sure why. It lets you submit the form with the default blank value 'State'
Would appreciate any help figuring out where my syntax is wrong on this form? If this looks foreign, using SLIM instead of HTML.
= f.select :state, nil, include_blank: 'State', required: true # not working
= render partial: 'addresses/states'
= f.text_field :zip, placeholder: 'Zip', required: true, pattern:'[0-9]*' # works
The states partial looks like this:
option value="AL" AL
option value="AK" AK
option value="AZ" AZ
option value="AR" AR
...
I'm using AngularJS with Rails and creating dynamic nested form items which are not registering in the AngularJS scope. They are assigned the 'ng-dirty' class.
I have an investor which has three houses, in my Angular controller I only assign the first 2 as I really want to set these through Rails instead.
$ (event) ->
app = angular.module "investor", []
app.controller("InvestorCtrl", ["$scope", ($scope) ->
$scope.houses = [
{ cost: "295000", value: "450000" },
{ cost: "600000", value: "620000" }
]
$scope.calc_totals = ->
# Initialise variables
cost = 0
value = 0
# Go through each house and calculate the total cost
for h in $scope.houses
cost = parseInt(cost) + parseInt(h.cost)
value = parseInt(value) + parseInt(h.value)
# Set the total
$scope.total_cost = cost
$scope.total_value = value
# Run the calculation at the start
# $scope.calc_totals()
])
angular.bootstrap document, ['investor']
Here is my form
%div{"ng-controller" => "InvestorCtrl"}
= form_for(#investor) do |f|
- if #investor.errors.any?
#error_explanation
%h2
= pluralize(#investor.errors.count, "error")
prohibited this investor from being saved:
%ul
- #investor.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :name
= f.text_field :name, "ng-model" => "name"
- i = 0
= f.fields_for :houses do |builder|
.field
= render :partial => "house", :locals => {:f => builder, :i => i}
- i = i + 1
.field
= f.label :total_cost
= f.number_field :total_cost, "ng-model" => "total_cost"
.field
= f.label :total_value
= f.number_field :total_value, "ng-model" => "total_value"
.actions
= f.submit
If I type in the first or second house 'cost' or 'value' then it updates the total_cost, but if I update the third house it will not update the total_cost.
Is there a way to dynamically tell angularjs to listen to these elements without assigning them in the controller?
You're actually going about this a little wrong, IMO. Since Angular can (and will) be handling the rendering of your repeating HTML for you, you don't necessarily need to do your HTML rendering on the server. All you need from your server is some JSON. If you want it to be rendered right off the bat, you just make sure your initial values are set up properly when you initialize your controller.
Inject $http or a custom made service into your controller, and pull the data you want directly from the server in JSON format, then plug it into your scope. If your HTML and directives are set up properly it will just render. From there all other logic will be the same.
The web is moving forward. And by forward, I mean all of that HTML rendering stuff you used to do on the server is actually starting to be done on the client more and more. And that service layer you used to use to get your data on your web server? Well it is your web server now.
I know this isn't a direct answer to your problem, but it will greatly simplify what you're trying to do. Otherwise you have a balancing act to perform that will get maddening pretty fast.
I have to submit multiple forms, I followed the advice of this post: How to submit multiple, duplicate forms from same page in Rails - preferably with one button
Note I'm still quite new to Rails/programming and some of my ways of doing things might not be ideal.
Here's my view:
= form_tag ([#event, #registration]) do
- x.times do
= render 'multi_form'
= submit_tag "Submit registrations"
The form (note that there are more fields):
- hidden_field_tag :event_id, :value => #event.id
.control-group
= label_tag :title
.controls
= select("registrations[][title]", :registration, Registration::TITLE)
.control-group
= label_tag :first_name
.controls
= text_field_tag "registrations[][first_name]"
.control-group
= label_tag :last_name
.controls
= text_field_tag "registrations[][last_name]"
.control-group
= label_tag :email
.controls
= text_field_tag "registrations[][email]"
The controller:
def create
array_number = 0
x.times do
#registration = Registration.new(params[:registrations][array_number])
#registration.save
UserMailer.registration_user_notify(#event, #registration).deliver
array_number = array_number + 1
end
respond_to do |format|
format.html {redirect_to thank_you_event_registrations_path(#event)}
end
end
When submitting it seems, to an extent, to be doing the right thing, for one it fires off an email to x unique email addresses, which makes me think that #registration contains the correct details in each loop - it's not saving to the database however. I can see that all the params are there in the log file, except that :title seems to be doing something bad (see below: but I'll focus on that later), the main thing I want it to do now is run though each array and save it as a new entry.
The log:
Parameters: {"utf8"=>"รข", "authenticity_token"=>"BQXm5fngW27z/3Wxy9qEzu6D8/g9YQIfBL+mFKVplgE=", "event_id"=>"7", "registrations"=>[{"title"=>{"registration"=>"Mrs"}, "first_name"=>"Person", "last_name"=>"One", "email"=>"charl#privatelabel.co.za"...
I'm hoping the info I provided is enough, any advice will be appreciated.
Thanks!
EDIT:
#iblue
It did the trick! It was a validation error and it's saving everything into different rows. Thank you very much!
One more thing if I may, any idea how the :title form part should be formatted in order to return paramater:
"title"=>"Mrs",
as opposed to:
"registrations"=>[{"title"=>{"registration"=>"Mrs"},
Thanks again!
You are not checking if #registration.save actually saves the record. It can return true or false. I guess it just silently fails.
If you use #registration.save!, it wile raise an exception when anything goes wrong. I guess there is some kind of validation error there.
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>')
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.